Swift UITableView委托和数据源声明和保留周期



据我所知,要在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的消息是无害的。

最新更新