使用工厂模式时如何将委托设置为视图控制器?

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)
    }
}