Gestão de Objective-C Setter Memória
-
13-09-2019 - |
Pergunta
Ainda um pouco confuso sobre o gerenciamento de memória Objective-C. Eu acho que a minha confusão decorre do que exatamente os meios disparo automático.
NSString *theBackendResponse = [[NSString alloc] initWithData:receivedData encoding:NSASCIIStringEncoding];
NSDictionary *accountDictionary = [theBackendResponse propertyList];
[viewController setAccountDictionary:accountDictionary];
Agora, o que devo fazer com o accountDictionary no método setAccountDictionary do meu controlador de vista? Agora eu apenas definir a variável de instância "accountDictionary" a tudo o que é retornado. Devo configurá-lo para um retido um, e em seguida, solte a única que voltou? O que devo dizer ao meu setter bloco de código semelhante, dado que o método PropertyList de NSString é autoreleased?
A propósito, se eu liberar theBackendResponse, eu vou perder o accountDictionary? Eu não supor ...
Solução
Chamando [objectInstance autorelease]
adiciona um objeto para o NSAutoreleasePool
atual. Quando isso piscina recebe uma mensagem drain
, ele envia uma release
a todos os objetos na piscina. Se algum dos retainCount desses objetos chega a 0, eles são desalocados naquele ponto. A finalidade do disparo automático é para que você possa marcar um objeto para ser lançado "em algum momento no futuro." Isto é especialmente útil para coisas como métodos que retornam um objeto recém-alocado, mas querem liberá-lo para que o chamador não tem que assumir a propriedade do objeto retornado. Um método pode ter esta aparência:
- (id)myMethod {
id myObj = [[SomeClass alloc] init];
...
return [myObj autorelease];
}
O chamador de myMethod
então retain
o valor de retorno se eles queriam se apropriar do valor retornado ou ignorá-lo se não. Quando o NSAutoreleasePool
atual é drenado, myObj
receberá uma mensagem de liberação. Se não houver outros objetos ele próprio (ou seja, ter enviado uma mensagem retain
), ele vai ficar desalocada.
Tudo isso é explicado no Gerenciamento de memória Cacau Guia de Programação . Mesmo se você já leu, vale sempre a pena uma outra leitura.
Assim, para responder às suas perguntas:
Primeiro, você deve liberar theBackendResponse
. Você vai vazar memória se não o fizer. Você não precisa saber o que accountDictionary
faz com a string: se ele precisa manter uma referência que vai ter retido theBackendResponse
. Você tem uma propriedade de theBackendResponse
porque você alloc
'd-lo, então você deve abrir mão de que a propriedade (via release
ou indiretamente via autorelease
).
Em segundo lugar, você deve manter ou copiar o argumento para setAccountDictionary:
se você quer manter uma referência a esse objeto ou valor, respectivamente. O método setter padrão é algo como isto (supondo que você não precisa semântica atômica):
-(void)setAccountDictionary:(NSDictionary*)newDict {
if(newDict != accountDictionary) {
id tmp = accountDictionary;
accountDictionary = [newDict copy]; //Since newDict may be mutable, we make a copy so that accountDictionary isn't mutated behind our back.
[tmp release];
}
}
Você também deve se lembrar de release
accountDictionary no método dealloc:
- (void)dealloc {
[accountDictionary release];
[super dealloc];
}
Uma vez que você parece estar usando NSViewController
, eu suponho que você está no Leopard (OS X 10.5) e nesse caso, você provavelmente deve estar usando @property
e se @synthesize
d getter / setter possível. Para fazer isso, adicione um
@property (copy,readwrite) NSDictionary * accountDictionary;
declaração ao @interface
classe. E adicionar uma directiva @synthesize accountDictionary;
no bloco @implementation
para sua classe controller.
Outras dicas
Em geral, um objeto ou método deve não precisa se preocupar sobre como outro é a gestão de memória. O fato de que alguém tenha autoreleased algo é irrelevante para você. É mais simples de pensar no conceito de propriedade . Então retain
e alguns outros métodos reivindica a posse, e release
e autorelease
cedê-lo. Se um objeto precisa manter uma referência para outro, deve reivindicar a posse durante o tempo que ele precisa. Assim, métodos setter normalmente reter ou copiar o novo valor e liberar ou autorelease o valor antigo.
Eu recomendo fortemente a leitura as diretrizes de gerenciamento de memória Cacau . Eles não são tudo o que longo ou complicado, e é muito importante para compreendê-los.
O método set acessador deve sempre copy
/ retain
o valor de entrada antes de liberar o velho, no caso em que o valor antigo é o único objeto que possui o novo valor:
-(void)setAccountDictionary:(NSDictionary*)newDict {
id old = accountDictionary;
accountDictionary = [newDict copy];
[old release];
}
Se accountDictionary
referido newDict
ea contagem de reter por newDict
foi de 1, a chamada para [accountDictionary release]
antes da chamada para [newDict copy]
faria com que a reter contar até cheguei a 0 e, portanto, liberar newDict
.
Como exemplo de código incorreto, onde nós liberamos o dicionário de idade e, em seguida, copie o novo dicionário:
-(void)setAccountDictionary:(NSDictionary*)newDict {
[accountDictionary release];
accountDictionary = [newDict copy];
}
e têm o seguinte código:
NSDictionary *dict = [obj accountDictionary];
[obj setAccountDictionary:dict];
É inventado, mas demonstra que no setter, accountDictionary
e newDict
referem-se à mesma instância. Se a manter a contagem é 1, a linha [accountDictionary release]
irá diminuir a contagem de reter a 0, e, assim, liberar a instância da memória. [newDict copy]
agora irá referir-se a uma instância inválido.
Apple descreve vários conceitos ao implementar acessores: Memória Gestão Accessor métodos
Se você pode usar Objective-C 2.0, eu iria com propriedades e sintaxe de ponto.
Propriedades são novos em Objective-C 2.0 e fornecer auto acessor geração.
No arquivo .h:
@property (retain) NSDictionary* accountDictionary;
Na implementação:
@synthesize accountDictionary;
Sintetizar gera métodos de acesso para a sua NSDictionary. (Se você quiser fornecer sua própria implementação, você também pode fazer isso)