6

以下代码来自 Apple 提供的 LazyTableImages 示例代码(source here)。

在他们的完成块中,他们有一个对 self 的引用,这应该会导致一个保留周期......但是我在 Xcode 中没有收到警告,而在我的类似代码中我会。

它是否正确?

也许我错过了这一点。

- (void)startIconDownload:(AppRecord *)appRecord forIndexPath:(NSIndexPath *)indexPath
{
    IconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];
    if (iconDownloader == nil) 
    {
        iconDownloader = [[IconDownloader alloc] init];
        iconDownloader.appRecord = appRecord;
        [iconDownloader setCompletionHandler:^{

            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

            // Display the newly loaded image
            cell.imageView.image = appRecord.appIcon;

            // Remove the IconDownloader from the in progress list.
            // This will result in it being deallocated.
            [self.imageDownloadsInProgress removeObjectForKey:indexPath];

        }];
        [self.imageDownloadsInProgress setObject:iconDownloader forKey:indexPath];
        [iconDownloader startDownload];  
    }
}
4

4 回答 4

4

您认为您看到的保留周期是因为该对象将下载器保存在字典中。

确实在块中存在对 self 的强引用,但是,只要始终运行完成处理程序,下载程序就会从字典中删除。最终这个字典将是空的,这意味着不会有对象持有自己,因此没有保留循环。

于 2013-07-27T19:08:41.140 回答
0

self没有指向 的强指针iconDownloader。它的创建和范围仅针对此方法:

IconDownloader *iconDownloader = [self.imageDownloadsInProgress objectForKey:indexPath];

如果iconDownloader是强属性 ( self.iconDownloader),那么 Xcode 会检测到强引用循环。

于 2013-07-27T18:29:55.667 回答
0

捕获自我本身不是保留周期。这是一个单一的参考。一个参考不能建立一个循环。通常的反模式是,对块的附加引用存储在 self 的强属性中。比有两个参考建立一个循环。

于 2013-07-27T18:40:46.597 回答
0

没有警告是因为编译器还不能检测所有可能的保留周期。

例如:

- (void)foo 
{
    _block = ^ { [self done]; }; // Warning: Possible retain cycle

    DSGenericBlock foo = ^ { [self done] }; 
    _block = foo;  // No warning.
}

如果要将块直接分配给“self”的实例变量,则会收到“可能的保留周期”警告。相反,该块被分配给另一个对象,然后由 self 保留,因此编译器不会检测到循环(即使循环确实存在)。

于 2013-07-27T19:38:34.313 回答