Por que não devo usar os acessadores do Objective C 2.0 no init / dealloc?

Na resposta do @mamalc a esta questão, ele afirma que “em geral, você não deve usar methods de access em dealloc (ou init).” Por que o mmalc diz isso?

As únicas razões pelas quais posso pensar são o desempenho e evitar efeitos colaterais desconhecidos de setters @ dynamics.

Discussão?

É tudo sobre o uso de código idiomaticamente consistente. Se você padronizar todo o seu código adequadamente, existem conjuntos de regras que garantem que o uso de um acessador no init / dealloc é seguro.

A grande questão é que (como disse mmalc) o código que configura o estado padrão das propriedades não deve passar por um acessador, porque leva a todos os tipos de problemas desagradáveis. O problema é que não há razão para o init ter que configurar o estado padrão de uma propriedade. Por uma série de razões, eu tenho me mudado para accessres que auto inicializo, como o exemplo simples abaixo:

- (NSMutableDictionary *) myMutableDict { if (!myMutableDict) { myMutableDict = [[NSMutableDictionary alloc] init]; } return myMutableDict; } 

Este estilo de boot de propriedade permite adiar um monte de código init que pode não ser realmente necessário. No caso acima, o init não é responsável por iniciar o estado das propriedades, e é completamente seguro (mesmo necessário) usar os acessadores no método init.

É certo que isso impõe restrições adicionais ao seu código, por exemplo, subclasss com acessadores customizados para uma propriedade na superclass devem chamar o acessador de superclasss, mas essas restrições não estão fora de sintonia com várias outras restrições comuns no Cocoa.

É basicamente uma diretriz para minimizar o potencial de erros.

Neste caso, há a (possibilidade) de que seu setter / getter possa inadvertidamente fazer suposições diretas ou indiretas sobre o estado do object. Essas suposições podem ser um problema quando o object está sendo configurado ou destruído.

Por exemplo, no código abaixo, o observador não sabe que ‘Example’ está sendo destruído e pode assumir que outras propriedades, que já foram liberadas, são válidas.

(Você poderia argumentar que seu object deveria remover todos os observadores antes de se derrubar, o que seria uma boa prática, e outra diretriz para evitar problemas inadvertidos).

 @implementation Example -(void) setFoo:(Foo*)foo { _foo = foo; [_observer onPropertyChange:self object:foo]; } -(void) dealloc { ... self.foo = nil; } @end 

Você respondeu sua própria pergunta:

  1. O desempenho pode ser uma razão perfeitamente adequada em si (especialmente se seus accessres forem atômicos).
  2. Você deve evitar quaisquer efeitos colaterais que os acessadores possam ter.

Este último é particularmente um problema se sua class pode ser subclassificada.

Não está claro, no entanto, por que isso é abordado especificamente em acessadores Objective-C 2 ? Os mesmos princípios se aplicam se você usa propriedades declaradas ou acessa os acessadores.

Pode ser que o setter tenha uma lógica que deve ser executada ou talvez a implementação tenha usado um ivar com nome diferente do getter / setter ou talvez dois ivars que precisam ser liberados e / ou ter seu valor definido como nulo. A única maneira certa é chamar o setter. É responsabilidade do incubador ser escrita de tal forma que efeitos colaterais indesejáveis ​​não ocorram quando chamados durante o init ou o dealloc.

De “cacau Design Patterns”, Buck, Yacktman, pp 115: “… não há nenhuma alternativa prática para usar assessores quando você usa variables ​​de instância sintetizada com o tempo de execução moderno Objective-C ou …”

Na verdade, para uma class que vem e vai com bastante frequência (como um controlador de visualização de detalhes), você deseja usar o acessador no init; caso contrário, você pode acabar liberando um valor em viewDidUnload que você tenta acessar mais tarde (eles mostram isso no CS193P …)

Você pode criar os mesmos problemas NÃO chamando o setter ao alocar / desalocar.

Eu não acho que você pode conseguir qualquer coisa usando reter / release diretamente no init / dealloc. Você acabou de mudar o conjunto de possíveis bugs.

Toda vez que você tem que pensar sobre a ordem de alocação de propriedade / desalocação.