所以我这里有一个涉及块的片段:
NSArray<Class> *acceptableClasses = @[[DesktopEntity class]];
__block NSInteger insertIdx = row;
[info enumerateDraggingItemsWithOptions:0 forView:_tableView classes:acceptableClasses searchOptions:nil usingBlock:^(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop)
{
DesktopEntity *entity = draggingItem.item;
[_tableContents insertObject:entity atIndex: insertIdx];
[_tableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:insertIdx] withAnimation:NSTableViewAnimationEffectGap];
draggingItem.draggingFrame = [_tableView frameOfCellAtColumn:0 row: insertIdx];
++insertIdx;
}];
它可以很好地编译,但我收到一个警告:
Block 隐式保留“self”;明确提及“self”以表明这是预期行为
我有点不明白它的意思。我通过在变量前输入 self 关键字来让警告消失:
[self.tableContents insertObject:entity atIndex: insertIdx];
[self.tableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:insertIdx] withAnimation:NSTableViewAnimationEffectGap];
draggingItem.draggingFrame = [self.tableView frameOfCellAtColumn:0 row: insertIdx];
++insertIdx;
但我也看到有人使用这样的结构
__weak typeof(self) weakSelf = self;
然后改用这个“weakSelf”,这里有什么区别?我的第一种方法是否错误?
该块确实保留了
self
您的操作方式。如果您确实知道块不会被存储以供运行时以后使用,那么没有问题;但是如果您不能确定块不会被存储以供以后使用,则可能会出现保留循环:块会保留,
self
但也许在幕后有人会保留该块,从而阻止self
其消失。在这种情况下,您应该使用“弱强舞蹈”,如问题末尾的代码所示,它通过使用
self
弱引用来打破保留循环。但情况是怎样的呢?这个块是否在后台保留?唉,运行时在后台的行为是不透明的。通过实验找出是否存在保留循环的一种方法是实现
dealloc
onself
以登录到控制台,并尝试按照您的方式使用代码运行应用程序。如果dealloc
从未打印,则self
永远不会被释放,因为您已经创建了一个保留循环,并且您知道需要弱-强舞蹈。就我个人而言,我倾向于只跳弱-强舞蹈,然后就此罢休。很多程序员都下意识地过度使用它,所以你怀疑它的必要性是正确的;但它没有坏处,而且可以带来好处,所以最好谨慎一点。