据我所知,要在swift中使用委托模式,我必须声明这样一个属性:
weak var delegate: TheDelegateProtocol!
和这样的协议:
@class_protocol protocol TheDelegateProtocol {
}
为了避免保留循环并坚持我们在目标c中习惯做的事情。
现在,如果我看一下UITableView定义中的内容,我只看到:
var dataSource: UITableViewDataSource!
var delegate: UITableViewDelegate!
:
protocol UITableViewDelegate : NSObjectProtocol, UIScrollViewDelegate {
[...]
}
我猜这与它实际上只是绑定到Objective C的事实有关,而Objective C的定义可能优先于swift的定义,但我在文档中找不到官方的解释。
这是出于同样的原因,通常许多Cocoa委托不是弱的。Cocoa的大部分代码不是用ARC编写的——因为它们先于ARC。它们手动管理内存,就像我们在过去美好的日子里不得不做的那样。所以他们没有得到电弧弱的乐趣(这是weak
在这里所表示的)。它们使用纯的、非内存管理的委托(和数据源)分配。它们没有保留,所以没有保留循环;但是由于它们没有使用ARC,所以它们不是安全的。
因此,你的责任是不要让这样的委托在主实例的生命周期内消失,以免它试图向悬空指针发送消息并崩溃。
你可以通过实验看到这一点(这是Objective-C,但你很快就会明白这一点):
self->_obj = [NSObject new];
nav.delegate = self->_obj // nav is our navigation controller, the root view controller
dispatch_async(dispatch_get_main_queue(), ^{
// cry havoc, and let slip the dogs of war!
self->_obj = nil; // releases obj - now what is nav.delegate pointing to??
NSLog(@"Nav Controller delegate: %@", ((UINavigationController*)self.window.rootViewController).delegate); // if you're lucky it might print something!
// or more likely it will just crash, or maybe print and *then* crash
});
那种崩溃正是ARC-weak所能防止的,因为它会自动用nil替换悬空指针——而在Objective-C中,指向nil的消息是无害的。