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兼容,可以说是一种更好的解决方式。