Então eu tenho esse trecho aqui que envolve um bloco:
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;
}];
compila bem, mas estou recebendo um aviso:
O bloco retém implicitamente 'self'; menciona explicitamente 'self' para indicar que este é o comportamento pretendido
Estou com alguma dificuldade para entender o que isso significa . Consegui fazer o aviso desaparecer apenas digitando a palavra-chave self antes das variáveis:
[self.tableContents insertObject:entity atIndex: insertIdx];
[self.tableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:insertIdx] withAnimation:NSTableViewAnimationEffectGap];
draggingItem.draggingFrame = [self.tableView frameOfCellAtColumn:0 row: insertIdx];
++insertIdx;
Mas também vi pessoas usando construções como
__weak typeof(self) weakSelf = self;
e então usar esse 'weakSelf' em vez disso, qual é a diferença aqui e minha primeira abordagem está errada?
O bloco mantém a maneira como
self
você está fazendo.Se você sabe com certeza que o bloco não está sendo armazenado para uso posterior pelo tempo de execução, tudo bem; mas se você não pode ter certeza de que o bloco não está sendo armazenado para uso posterior, você corre o risco de um ciclo de retenção: o bloco retém,
self
mas talvez, nos bastidores, alguém esteja retendo o bloco, impedindo assimself
que ele deixe de existir.E nesse caso, você deve usar a "dança fraco-forte" , conforme ilustrado no código no final da sua pergunta, que quebra o ciclo de retenção ao fazer referência a
self
uma referência fraca.Mas qual é o caso? Esse bloco é retido nos bastidores ou não? Infelizmente, o comportamento do tempo de execução nos bastidores é opaco. Uma maneira de descobrir experimentalmente se há um ciclo de retenção é implementar
dealloc
onself
para registrar no console e tentar executar o aplicativo com o código do seu jeito. Se a impressão emdealloc
nunca acontecer, entãoself
nunca será desalocado porque você criou um ciclo de retenção e sabe que a dança fraco-forte é necessária.Pessoalmente, eu estaria inclinado a apenas fazer a dança do fraco-forte e deixar para lá. Ele é usado em excesso de forma impulsiva por muitos programadores, então você está certo em duvidar de sua necessidade aqui; mas ele não faz mal e pode fazer bem, então pode ser melhor errar por excesso de cautela.