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

时间:2017-05-15 19:00:06

标签: ios swift delegates protocols factory-method

我有UIViewController并且在viewDidLoad方法中我有一个返回视图的工厂方法。

我正在尝试将UIViewController设置为这些不同视图的委托。但是,每个视图都有不同的委托,当我实际调用工厂方法时,它只返回一个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
    }
}
}

2 个答案:

答案 0 :(得分:2)

你有各种选择。您可以使用以下方法:

您可以使UIView的所有不同自定义子类都来自具有委托属性的公共祖先。 (我们将其称为CustomView类。)然后,您可以使ViewFactory返回该类型的对象。

以下是自定义视图的基类:

class CustomView: UIView {
  public weak var delegate: AnyObject?
  //Put any other shared properties/methods of all CustomView objects here
}

您作为CustomView子类的视图可能如下所示:

class OneView: CustomView {
  //Extra properties/methods for a OneView object
}

class TwoView: CustomView {
  //Extra properties/methods for a TwoView object
}

最后,重构您的ViewFactory以返回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...
    }
}

答案 1 :(得分:0)

您可能更好地使用协议,而不是使用类继承。协议仅强制实施类的接口。您可以在一个类中采用多个协议。您只能从一个类继承。

如果您希望在代理中具有通用功能,则为您的委托类创建协议

protocol DelegateProtocol {
    func oneView(date: Date)
}

确保所有代表都采用此协议。

class MyDelegate : DelegateProtocol {
    func oneView(date: Date) {
    }
    ...
}

创建另一个包含对此委托的引用的协议,并确保所有视图类通过其类定义或类扩展定义采用此协议

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

之后,只要您设置了所有视图类以采用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)
    }
}