在ARC中,我们通常用weak关键字来修饰delegate,在delegate的实际对象被释放时,其就会被重置为nil,有效避免循环引用。在Swift中,我们当然也希望这么做。但是当我们尝试书写这样的代码的时候,编译器就会报错:
protocol TestClassDelegate {
func method()
}
class TestClass {
weak var delegate: TestClassDelegate?
}
class ViewController: UIViewController, TestClassDelegate {
var testInstance: TestClass?
override func viewDidLoad() {
super.viewDidLoad()
testInstance = TestClass()
testInstance?.delegate = self
}
}
// weak var delegate: TestClassDelegate? 这句会编译报错
'weak' may only be applied to class and class-bound protocol types, not 'TestClassDelegate'
这是因为 Swift 的protocol 是可以被除了 class 以外的其他类型遵守的,而对于像 struct 或是 enum 这样的类型,本身就不通过引用计数来管理内存,所以也不可能用 weak 这样的 ARC 的概念来进行修饰。
想要在 Swift 中使用 weak delegate,我们就需要将 protocol 声明为 Objective-C 的,这可以通过在 protocol 前面加上 @objc 关键字来达到,Objective-C 的 protocol 都只有类能实现,因此使用 weak 来修饰就合理了:
@objc protocol TestClassDelegate {
func method()
}
另一种可能更好的办法是在 protocol 声明的名字后面加上 class,这可以为编译器显示地指明这个 protocol 只能由 class 来实现:
protocol TestClassDelegate: class {
func method()
}
相比起添加关键字 @objc,后一种方法更能表现出问题的实质,同时也避免了过多的不必要的 Objective-C 兼容,可以说是一种更好的解决方式。