Estou navegando no maravilhoso blog mantido por Scott Stevenson e estou tentando entender um conceito fundamental do Objective-C de atribuir delegados a propriedade 'assign' property vs 'reter'. Observe que os dois são iguais em um ambiente de coleta de lixo. Estou principalmente preocupado com um ambiente não baseado em GC (por exemplo, iPhone).
Diretamente do blog de Scott:
"A palavra-chave assign irá gerar um setter que atribui o valor diretamente à variável de instância, em vez de copiá-lo ou retê-lo. Isso é melhor para tipos primitivos como NSInteger e CGFloat, ou objetos que você não possui diretamente, como delegados".
O que significa que você não é o proprietário direto do objeto delegado? Normalmente retiro meus delegados, porque, se não quero que eles desapareçam no abismo, reter cuidará disso para mim. Normalmente, abstraio o UITableViewController do seu respectivo dataSource e também delego. Também guardo esse objeto em particular. Quero garantir que ele nunca desapareça, para que meu UITableView sempre tenha seu representante por perto.
Alguém pode explicar melhor onde / por que estou errado, para entender esse paradigma comum na programação do Objective-C 2.0 de usar a propriedade assign nos delegados em vez de reter?
Obrigado!
fonte
Respostas:
O motivo de evitar reter delegados é que você precisa evitar um ciclo de retenção:
A cria B A se define como delegado de B ... A é liberado por seu proprietário
Se B tivesse retido A, A não seria liberado, pois B é o dono de A, portanto, o acordo de A nunca seria pago, causando vazamento de A e B.
Você não deve se preocupar com o desaparecimento de A porque ele possui B e, portanto, se livra dele em desalocação.
fonte
weak
faz? A questão é por que usar emassign
vez deweak
?assign
vez deretain
. A questão é mais antiga que o ARC;weak
estrong
(o último sendo sinônimo deretain
) não existia até o ARC ser introduzido. Você deve fazer sua pergunta sobreweak
vs.assign
separadamente.Porque o objeto que envia as mensagens de delegado não é o proprietário do delegado.
Muitas vezes, é o contrário, como quando um controlador se define como o delegado de uma visão ou janela: o controlador é o proprietário da visão / janela; portanto, se a visão / janela possui o seu delegado, os dois objetos se pertencem. É claro que este é um ciclo de retenção, semelhante a um vazamento com a mesma consequência (objetos que deveriam estar mortos permanecem vivos).
Outras vezes, os objetos são pares: nenhum deles é dono do outro, provavelmente porque ambos pertencem ao mesmo terceiro objeto.
De qualquer forma, o objeto com o delegado não deve reter seu delegado.
(A propósito, há pelo menos uma exceção. Não me lembro o que era e acho que não havia uma boa razão para isso.)
Adendo (adicionado 19/05/2012): No ARC, você deve usar em
weak
vez deassign
. Referências fracas são definidasnil
automaticamente quando o objeto morre, eliminando a possibilidade de o objeto delegador acabar enviando mensagens para o delegado morto.Se você estiver longe do ARC, por algum motivo, altere pelo menos as
assign
propriedades que apontam para objetosunsafe_unretained
, o que torna explícito que essa é uma referência não retida, mas não zero, a um objeto.assign
permanece apropriado para valores não-objeto tanto no ARC quanto no MRC.fonte
NSURLConnection
mantém seu delegado.weak
, mas isso não responde à pergunta original: por que a Apple usa emassign
vez deweak
?assign
vez de retidas ";weak
não existia quando foi solicitado. Sua pergunta é diferente, e você deve perguntar separadamente. Eu ficaria feliz em responder.Observe que, quando você tem um delegado designado, é muito importante sempre definir esse valor de delegado para zero quando o objeto for desalocado - portanto, um objeto deve sempre ter o cuidado de anular as referências de delegado no desalocamento, se não tiver. feito em outro lugar.
fonte
Uma das razões por trás disso é evitar ciclos de retenção. Apenas para evitar o cenário em que ambos os objetos A e B se referem um ao outro e nenhum deles é liberado da memória.
A atribuição aguda é melhor para tipos primitivos como NSInteger e CGFloat, ou objetos que você não possui diretamente, como delegados.
fonte