我刚刚完成调试一个非常讨厌的UIViewController
泄漏,这样即使在调用dismissViewControllerAnimated
之后UIViewController也不会被释放。为什么在performBatchUpdates中对父UIViewController的强引用泄漏了一个活动?
我的问题追查到下面的代码块:
self.dataSource.doNotAllowUpdates = YES;
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]];
} completion:^(BOOL finished) {
self.dataSource.doNotAllowUpdates = NO;
}];
基本上,如果我做一个呼叫performBatchUpdates
后立即调用dismissViewControllerAnimated
的UIViewController中被泄露和UIViewController
的dealloc
方法不会被调用。 UIViewController永远挂起。
有人可以解释这种行为吗?我假设performBatchUpdates
运行一段时间间隔,比如500毫秒,所以我会假设在所述间隔之后,它会调用这些方法,然后触发dealloc。
的修复似乎是这样的:
self.dataSource.doNotAllowUpdates = YES;
__weak __typeof(self)weakSelf = self;
[self.collectionView performBatchUpdates:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf) {
[strongSelf.collectionView reloadItemsAtIndexPaths:@[indexPath]];
}
} completion:^(BOOL finished) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (strongSelf) {
strongSelf.dataSource.doNotAllowUpdates = NO;
}
}];
注意,BOOL
成员变量,doNotAllowUpdates
,是我添加防止任何类型的数据源/的CollectionView更新到performBatchUpdates一个呼叫正在运行时的变量。
我在网上搜索了一下关于我们是否应该使用performBatchUpdates
中的weakSelf/strongSelf模式的讨论,但没有在这个问题上找到任何具体的内容。
我很高兴能够深入到这个bug的底部,但我更喜欢更聪明的iOS开发人员向我解释我看到的这种行为。
看看您是否可以确定是否导致保留周期的更新块或完成块,这会很有趣。正如你所说的,它们都不应该永久保留它们的块 - 我只能假设当集合视图从其超级视图中被移除时,它将停止运行任何批量更新,并且不会调用或释放完成块。在我看来,值得雷达。 – jrturton
@jrturton啊这似乎是最有可能的解释!基于这种见解,我会看看是否可以在调试器中重新制作这个代码。 – esilver
@ jrturton alas无法在调试器中重现......看起来好像两个块至少总是被调用。也许内部不是无效的,虽然如果解雇被称为中间? – esilver