delegate

代码

Cocoa开发中协议-委托(protocol-delegate)模式是一种常用的设计模式,它贯穿于整个Cocoa框架中,为代码之间的关系清理和解耦合做出了不可磨灭的贡献。

在ARC中,对于一般的delegate,我们会在声明中将其指定为weak,在这个delegate实际的对象被释放的时候,会被重置回 nil 。这可以保证即使delegate已经不存在时,我们也不会由于访问到已被回收的内存而导致崩溃。ARC的这个特性杜绝了Cocoa开发中一种非常常见的崩溃错 误,说是救万千程序员于水火之中也毫不为过。

在Swift中我们当然也会希望这么做。但是当我们尝试书写这样的代码的时候,编译器不会让我们通过:

protocol MyClassDelegate {
    func method()
}

class MyClass {
    weak var delegate: MyClassDelegate?
}


class ViewController: UIViewController, MyClassDelegate {

    var someInstance: MyClass!

    override func viewDidLoad() {
        super.viewDidLoad()

        someInstance = MyClass()
        someInstance.delegate = self
    }

    func method() {
        print("Do something")
    }

    //...
}
// weak var delegate: MyClassDelegate? 编译错误
// 'weak' may only be applied to class and class-bound protocol types, not 'MyClassDelegate'

这是因为Swift的 protocol 是可以被除了 class 以外的其他类型遵守的,而对于像 struct 或是 enum 这样的类型,本身就不通过引用计数来管理内存,所以也不可能用 weak 这样的ARC的概念来进行修饰。

想要在Swift中使用weak delegate,我们就需要将protocol限制在class内。一种做法是将protocol声明为Objective-C的,这可以通过在protocol前面加上关键字 @objc 来达到,Objective-C的protocol都只有类能实现,因此使用weak来修饰就合理了:

@objc protocol MyClassDelegate {
    func method()
}

另一种可能更好的办法是在protocol声明的名字后面加上 class ,这可以为编译器显式地指明这个protocol只能由 class 来实现。

protocol MyClassDelegate: class {
    func method()
}

相比起添加 @objc ,后一种方法更能表现出问题的实质,同时也避免了过多的不必要的Objective-C兼容,可以说是一种更好的解决方式。

results matching ""

    No results matching ""