使用工厂模式时如何将委托设置为视图控制器?
How do you set delegate to a view controller when using a factory pattern?
我有一个 UIViewController
并且在 viewDidLoad 方法中我有一个 returns 视图的工厂方法。
我正在尝试将 UIViewController 设置为这些不同视图的代表。但是,每个视图都有不同的委托,当我实际调用工厂方法时,它只是 returns 一个 UIView。 UIView 当然不知道委托。
我不能很好地将 delegate = ViewController
放在 ViewFactory 本身中,因为这意味着它会知道我的 ViewController,这很糟糕。我的另一个想法是,我可以将所有视图转换为它们实际的样子,以便他们了解委托,但这让我复制了一堆代码,所以我想知道是否有人可以在这里指出我正确的方向?
ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//This of course would have data to populate it, but I cannot show it here.
let data = [ViewTemplate]()
let someView = ViewFactory.getView((data?[currentCount - 1])!)
//so here is where I thought I could add
//someView.delegate
//but of course it is just a UIView that is returned so it
//doesn't know anything about a delegate
someContainerView.addSubview(someView)
}
}
struct ViewFactory {
static func getView(_ template: ViewTemplate) -> UIView {
switch template.viewType {
case .One:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("OneView", owner: self, options: nil)?.first as! OneView
containerView.label.text = template.text
return containerView
case .Two:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("TwoView", owner: self, options: nil)?.first as! TwoView
containerView.label.text = template.text
return containerView
case .Three:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("ThreeView", owner: self, options: nil)?.first as! ThreeView
containerView.label.text = template.text
return containerView
case .Four:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("FourView", owner: self, options: nil)?.first as! FourView
containerView.label.text = template.text
return containerView
case .Five:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("FiveView", owner: self, options: nil)?.first as! FiveView
containerView.label.text = template.text
return containerView
case .Six:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("SixView", owner: self, options: nil)?.first as! SixView
containerView.label.text = template.text
return containerView
}
}
}
你有多种选择。这是您可以使用的一种方法:
您可以使 UIView
的所有不同的自定义子 class 继承自具有委托 属性 的共同祖先。 (让我们称它为 CustomView
class。)然后你可以制作你的 ViewFactory
return 那种类型的对象。
这是自定义视图的基础class:
class CustomView: UIView {
public weak var delegate: AnyObject?
//Put any other shared properties/methods of all CustomView objects here
}
您的 CustomView 子class视图可能如下所示:
class OneView: CustomView {
//Extra properties/methods for a OneView object
}
class TwoView: CustomView {
//Extra properties/methods for a TwoView object
}
最后,将您的 ViewFactory 重构为 return 类型 CustomView
的视图,而不是普通的 UIView
:
struct ViewFactory {
static func getView(_ template: ViewTemplate) -> CustomView {
switch template.viewType {
case .One:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("OneView", owner: self, options: nil)?.first as! OneView
containerView.label.text = template.text
return containerView
//Your other cases...
}
}
与其使用 class 继承,不如在这里使用协议更好。协议仅在 class 上强制执行接口。您可以在 class 中采用多个协议。您只能继承一个 class。
如果您希望在您的委托中拥有共同的功能,那么请为您的委托创建一个协议 classes
protocol DelegateProtocol {
func oneView(date: Date)
}
确保您的所有代表都采用此协议。
class MyDelegate : DelegateProtocol {
func oneView(date: Date) {
}
...
}
创建另一个包含对此委托的引用的协议,并确保您的所有视图 classes 通过其 class 定义或 class 扩展定义采用此协议
class DelegateReferenceProtocol {
var myDelegate : DelegateProtocol? {get set}
}
class OneView : DelegateReferenceProtocol {
var myDelegate : DelegateProtocol? {get {} set(value) {}}
...
}
extension TwoView : DelegateReferenceProtocol {
var myDelegate : DelegateProtocol? {get {} set(value) {}}
...
}
之后,只要您设置了所有视图 classes 以采用 DelegateReferenceProtocol 协议,您的 viewDidLoad 函数将如下所示
class ViewController: UIViewController, DelegateProtocol {
override func viewDidLoad() {
super.viewDidLoad()
//This of course would have data to populate it, but I cannot show it here.
let data = [ViewTemplate]()
let someView = ViewFactory.getView((data?[currentCount - 1])!)
someView.myDelegate = self
someContainerView.addSubview(someView)
}
}
我有一个 UIViewController
并且在 viewDidLoad 方法中我有一个 returns 视图的工厂方法。
我正在尝试将 UIViewController 设置为这些不同视图的代表。但是,每个视图都有不同的委托,当我实际调用工厂方法时,它只是 returns 一个 UIView。 UIView 当然不知道委托。
我不能很好地将 delegate = ViewController
放在 ViewFactory 本身中,因为这意味着它会知道我的 ViewController,这很糟糕。我的另一个想法是,我可以将所有视图转换为它们实际的样子,以便他们了解委托,但这让我复制了一堆代码,所以我想知道是否有人可以在这里指出我正确的方向?
ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//This of course would have data to populate it, but I cannot show it here.
let data = [ViewTemplate]()
let someView = ViewFactory.getView((data?[currentCount - 1])!)
//so here is where I thought I could add
//someView.delegate
//but of course it is just a UIView that is returned so it
//doesn't know anything about a delegate
someContainerView.addSubview(someView)
}
}
struct ViewFactory {
static func getView(_ template: ViewTemplate) -> UIView {
switch template.viewType {
case .One:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("OneView", owner: self, options: nil)?.first as! OneView
containerView.label.text = template.text
return containerView
case .Two:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("TwoView", owner: self, options: nil)?.first as! TwoView
containerView.label.text = template.text
return containerView
case .Three:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("ThreeView", owner: self, options: nil)?.first as! ThreeView
containerView.label.text = template.text
return containerView
case .Four:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("FourView", owner: self, options: nil)?.first as! FourView
containerView.label.text = template.text
return containerView
case .Five:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("FiveView", owner: self, options: nil)?.first as! FiveView
containerView.label.text = template.text
return containerView
case .Six:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("SixView", owner: self, options: nil)?.first as! SixView
containerView.label.text = template.text
return containerView
}
}
}
你有多种选择。这是您可以使用的一种方法:
您可以使 UIView
的所有不同的自定义子 class 继承自具有委托 属性 的共同祖先。 (让我们称它为 CustomView
class。)然后你可以制作你的 ViewFactory
return 那种类型的对象。
这是自定义视图的基础class:
class CustomView: UIView {
public weak var delegate: AnyObject?
//Put any other shared properties/methods of all CustomView objects here
}
您的 CustomView 子class视图可能如下所示:
class OneView: CustomView {
//Extra properties/methods for a OneView object
}
class TwoView: CustomView {
//Extra properties/methods for a TwoView object
}
最后,将您的 ViewFactory 重构为 return 类型 CustomView
的视图,而不是普通的 UIView
:
struct ViewFactory {
static func getView(_ template: ViewTemplate) -> CustomView {
switch template.viewType {
case .One:
let bundle = Bundle.main
let containerView = bundle.loadNibNamed("OneView", owner: self, options: nil)?.first as! OneView
containerView.label.text = template.text
return containerView
//Your other cases...
}
}
与其使用 class 继承,不如在这里使用协议更好。协议仅在 class 上强制执行接口。您可以在 class 中采用多个协议。您只能继承一个 class。
如果您希望在您的委托中拥有共同的功能,那么请为您的委托创建一个协议 classes
protocol DelegateProtocol {
func oneView(date: Date)
}
确保您的所有代表都采用此协议。
class MyDelegate : DelegateProtocol {
func oneView(date: Date) {
}
...
}
创建另一个包含对此委托的引用的协议,并确保您的所有视图 classes 通过其 class 定义或 class 扩展定义采用此协议
class DelegateReferenceProtocol {
var myDelegate : DelegateProtocol? {get set}
}
class OneView : DelegateReferenceProtocol {
var myDelegate : DelegateProtocol? {get {} set(value) {}}
...
}
extension TwoView : DelegateReferenceProtocol {
var myDelegate : DelegateProtocol? {get {} set(value) {}}
...
}
之后,只要您设置了所有视图 classes 以采用 DelegateReferenceProtocol 协议,您的 viewDidLoad 函数将如下所示
class ViewController: UIViewController, DelegateProtocol {
override func viewDidLoad() {
super.viewDidLoad()
//This of course would have data to populate it, but I cannot show it here.
let data = [ViewTemplate]()
let someView = ViewFactory.getView((data?[currentCount - 1])!)
someView.myDelegate = self
someContainerView.addSubview(someView)
}
}