Pergunta

Qual é a diferença entre as 2 formas a seguir para alocar e o init um objeto?

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

e

self.aController= [[AController alloc] init];

A maioria do exemplo de maçã usar o primeiro método. Por que você iria alocar, o init e objeto e, em seguida, solte imediatamente?

Foi útil?

Solução

Cada objeto tem uma contagem de referência. Quando ele vai para 0, o objeto é desalocada.

Assumindo que a propriedade foi declarada como @property (retain):

Seu primeiro exemplo, linha por linha:

  1. O objeto é criado por alloc, ele tem uma contagem de referência de 1.
  2. O objeto é entregue ao método self de setAController:, que envia uma mensagem retain (porque o método não sabe onde o objeto está vindo), incrementando a sua contagem de referência para 2.
  3. O código de chamada não precisa mais o objeto em si, por isso chama release, diminuindo a contagem de referência para 1.

O segundo exemplo faz basicamente as etapas 1 e 2, mas não 3, então no final contagem de referência do objeto é 2.

A regra é que se você criar um objeto, você é responsável por liberá-lo quando você está feito com ele. No seu exemplo, o código é feito com tempAController depois que define a propriedade. É responsabilidade do método setter para retain chamada, se ele precisa esse objeto para ficar por aqui.

É importante lembrar que self.property = foo; em Objective-C é realmente apenas uma abreviação para [self setProperty:foo]; e que o método setProperty: vai ser manter ou copiar objetos conforme necessário.

Se a propriedade foi declarada @property (copy), em seguida, o objeto teria sido copiado em vez de mantidos. No primeiro exemplo, o objeto original seria libertado imediatamente; No segundo exemplo, a contagem de referência do objeto original seria 1 mesmo que deve ser 0. Então, você ainda gostaria de escrever o código da mesma forma.

Se a propriedade foi declarada @property (assign), então self não está reivindicando a posse do objeto, e as necessidades de outra pessoa alguém para retê-lo. Neste caso, o primeiro exemplo seria incorreto. Esses tipos de propriedades são raros, geralmente utilizado apenas para os delegados de objetos.

Outras dicas

Como outros já mencionado, os dois trechos de código que você mostra não são equivalentes (por motivos de gerenciamento de memória). Quanto ao porquê do primeiro é escolhido em detrimento do último:

A formulação correta do último seria

self.aController= [[[AController alloc] init] autorelease];

Em comparação com o primeiro, isso adiciona uma sobrecarga adicional através do uso da piscina disparo automático, e em algumas circunstâncias levará à vida útil do objeto que está sendo desnecessariamente prolongado (até a piscina disparo automático é liberado) que irá aumentar consumo de memória do seu aplicativo.

A outra aplicação "possível" (dependendo de onde o exemplo é de) é simplesmente:

aController = [[AController alloc] init];

No entanto, definir uma variável de instância diretamente é fortemente desencorajada em qualquer lugar diferente em um método init ou dealloc. Em outros lugares você deve sempre usar métodos de acesso.

Isto leva-nos então para a implementação mostrada no código de exemplo:

AController *tempAController = [[AController alloc] init];
self.aController = tempAController;
[tempAController release];

Esta segue as melhores práticas desde:

  • Evita disparo automático;
  • Faz a semântica de gerenciamento de memória imediatamente claro;
  • Ele usa um método de acesso para definir a variável de instância.

Note também que o seu desejo de cortar o baixo código para uma linha é por isso que muitas pessoas usam Autorelease:

self.aController = [[[AController alloc] init] autorelease];

Embora, em teoria, na disparo automático iPhone é de alguma forma mais caro (nunca ouvi uma explicação clara por que) e, assim, você pode querer liberar explicitamente o direito depois de atribuir o objeto em outro lugar.

Se você estiver usando o Xcode, pode ajudar a detectar esse código com o analisador estático. Basta clicar em Construir >> Desenvolver e analisar

text alt

Isto irá mostrar uma mensagem muito útil em tais pedaços de código.

text alt

Uma outra coisa a notar é que o seu exemplo depende da definição @property de aController também.

Se foram definidos como @property (readwrite, retain) id aController; então seu exemplo de obras, enquanto que, se ela é definida como @property (readwrite, assign) id aController; então a chamada extra para liberação faria com que seu objeto a ser desalocada.

Você também pode fazer

@property (nonatomic, retain)AController *aController;
...
self.aController= [[AController alloc] init];
[aController release];

com uma propriedade de retenção, e que iria funcionar da mesma maneira, mas o seu melhor para usar a outra forma (por retenção de propriedades) porque é menos confuso, que o código faz com que pareça que você atribui aController e, em seguida, ele é excluído da memória , quando na verdade não porque setAController mantém-lo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top