可以动态地将逻辑附加到方法吗?

时间:2016-02-26 20:35:13

标签: ios swift swift2 protocol-extension

我想从一个类的init动态地将闭包附加到另一个方法。例如,对于UIViewController,我想添加一个扩展名,以便我可以在viewDidLoad事件中注入代码。我尝试了类似下面的内容,但它不起作用:

class BaseViewController: UIViewController, MyProtocol {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // Setup and bind
        configure()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Call MyProtocol.myDidLoad but not explicitly!
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        // Call viewWillAppear but not explicitly!
    }

}

protocol MyProtocol { }

extension MyProtocol where Self: UIViewController {

    func configure() {
        // Something like below isn't possible???
        self.viewDidLoad += myDidLoad
        self.viewWillAppear += myWillAppear
    }

    func myDidLoad() {
        // Something
    }

    func myWillAppear() {
        // Something
    }
}

实现这一点是否可行,而没有明确调用UIViewController中的协议功能?我不想通过我的所有课程并为每个函数调用协议函数。这将是乏味,冗余的代码,很容易被忽视。有更优雅的方式吗?

更新

考虑到这些限制,下面是我能想到的唯一方法,但它是使用继承而不是组合而且仍然要求我明确调用协议扩展函数,这不是我想要的做:

class FirstViewController: BaseViewController {

}

class BaseViewController: UIViewController, MyProtocol, MyProtocol2, MyProtocol3 {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        // Configure protocols
        configure(self as MyProtocol)
        configure(self as MyProtocol2)
        configure(self as MyProtocol3)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Load protocols
        viewDidLoad(self as MyProtocol)
        viewDidLoad(self as MyProtocol2)
        viewDidLoad(self as MyProtocol3)
    }

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)

        // Prerender protocols
        viewWillAppear(self as MyProtocol)
        viewWillAppear(self as MyProtocol2)
        viewWillAppear(self as MyProtocol3)
    }

}

protocol MyProtocol { }

extension MyProtocol where Self: UIViewController {

    func configure(delegate: MyProtocol) {
        print("MyProtocol.configure")
    }

    func viewDidLoad(delegate: MyProtocol) {
        print("MyProtocol.viewDidLoad")
    }

    func viewWillAppear(delegate: MyProtocol) {
        print("MyProtocol.viewWillAppear")
    }
}

protocol MyProtocol2 { }

extension MyProtocol2 where Self: UIViewController {

    func configure(delegate: MyProtocol2) {
        print("MyProtocol2.configure")
    }

    func viewDidLoad(delegate: MyProtocol2) {
        print("MyProtocol2.viewDidLoad")
    }

    func viewWillAppear(delegate: MyProtocol2) {
        print("MyProtocol2.viewWillAppear")
    }
}

protocol MyProtocol3 { }

extension MyProtocol3 where Self: UIViewController {

    func configure(delegate: MyProtocol3) {
        print("MyProtocol3.configure")
    }

    func viewDidLoad(delegate: MyProtocol3) {
        print("MyProtocol3.viewDidLoad")
    }

    func viewWillAppear(delegate: MyProtocol3) {
        print("MyProtocol3.viewWillAppear")
    }
}

//Output:
//MyProtocol.configure
//MyProtocol2.configure
//MyProtocol3.configure
//MyProtocol.viewDidLoad
//MyProtocol2.viewDidLoad
//MyProtocol3.viewDidLoad
//MyProtocol.viewWillAppear
//MyProtocol2.viewWillAppear
//MyProtocol3.viewWillAppear

这违背了面向协议编程的整个目的。在iOS开发的范围内工作时,Swift可以处理一种优雅的方法,或者在这种情况下POP不起作用吗?

1 个答案:

答案 0 :(得分:4)

你想做的事情是不可能的,因为Swift和Objective-C都是单继承语言。

扩展只能添加其他方法,它不能覆盖方法。只有子类可以覆盖现有类中的方法。考虑多个扩展覆盖同一方法的情况 - 应该调用哪一个?所有这些?,如果是这样的话?见The Diamond Problem

最简单的方法是创建一个提供所需功能的UIViewController子类。虽然程序员可以创建一个符合协议的类但不会对正确的超类进行子类化,但考虑到类和协议是在同一行上输入的,这将是一个非常愚蠢的错误。