Objective C NSString * propriedade reter contagem oddity
-
03-07-2019 - |
Pergunta
Eu tenho a seguinte classe de exemplo:
Test.h:
@interface Test : UIButton {
NSString *value;
}
- (id)initWithValue:(NSString *)newValue;
@property(copy) NSString *value;
Test.m:
@implementation Test
@synthesize value;
- (id)initWithValue:(NSString *)newValue {
[super init];
NSLog(@"before nil value has retain count of %d", [value retainCount]);
value = nil;
NSLog(@"on nil value has retain count of %d", [value retainCount]);
value = newValue;
NSLog(@"after init value has retain count of %d", [value retainCount]);
return self;
}
Que produz o seguinte resultado:
2008-12-31 09:31:41.755 Concentration[18604:20b] before nil value has retain count of 0
2008-12-31 09:31:41.756 Concentration[18604:20b] on nil value has retain count of 0
2008-12-31 09:31:41.757 Concentration[18604:20b] after init value has retain count of 2147483647
Eu estou chamando-o como:
Test *test = [[Test alloc] initWithValue:@"some text"];
não deve ter um valor de manter a contagem de 1? o que estou perdendo?
Obrigado por sua ajuda.
Solução 5
Você tem uma referência a uma cadeia imutável. Atribuição não precisa copiar o valor (os dados string), já que é imutável. Se você fizer uma operação mutável, como valor = [newValue uppercaseString], então ele deve copiar os bits em valor e de valor manter a contagem incrementado.
Outras dicas
Não olhe para manter a contagem. Eles não são úteis e só vai enganá-lo - você não pode ter a certeza de que nada mais é reter um objeto, que um objeto que você começa de algum lugar não é compartilhada
. Em vez disso, concentrar-se em propriedade do objeto e seguir o regras de gerenciamento de memória cacau para a carta. Dessa forma, o gerenciamento de memória será correta não importa o que otimizações Cacau pode estar fazendo nos bastidores para você. (Por exemplo, implementar -copy
como apenas -retain
para objetos imutáveis.)
Além disso, é crítico para entender a diferença entre Propriedades de seus objetos e variáveis ?? exemplo dentro de seus objetos. No código da sua pergunta, você está atribuindo um valor a uma variável de instância. Essa variável de instância é apenas isso: uma variável. Atribuindo a ele irá se comportar como qualquer outra atribuição de variável. Para usar a propriedade, você deve usar sintaxe de ponto ou sintaxe suporte para realmente invocar método setter da propriedade:
self.value = newValue; // this is exactly equivalent to the next line
[self setValue:newValue]; // this is exactly equivalent to the previous line
O código gerado para a sintaxe de ponto e a sintaxe suporte é idêntica, e nem irá acessar a variável de instância diretamente.
Você está passando uma string literal. O compilador provavelmente aloca-lo na memória estática e define a manter a contagem para o valor máximo possível.
Tente uma string alocada dinamicamente em vez disso e ver o que acontece.
NSString* string = [[NSString alloc] initWithString: @"some text"];
Test* test = [[Test alloc] initWithValue: string];
Você está passando em uma constante string, que realmente não pode ser desalocada. Eu acho que é provavelmente 2147483647 UINT_MAX, que basicamente significa que o objeto não pode ser liberado.
Eu acho que você quer fazer isso:
self.value = newValue;
que irá invocar o setter da propriedade e fazer com que a cópia de ocorrer. "Value = newValue" simplesmente atribui um valor de ponteiro para a variável de instância.
Você não deve estar prestando atenção ao reter contagem, basta seguir as regras de gerenciamento de memória Cacau. http://iamleeg.blogspot.com/2008/12/cocoa- memória de management.html
hmm .. estamos chegando mais perto.
parece que manter a contagem de newValue também é 2147483647.
Eu tentei alocar dinamicamente a string em vez com os mesmos reter resultados da contagem.
Eu encontrei um artigo útil aqui: http://www.cocoadev.com/index. pl? NSString
FTA:
O NSString retornado por @ "" necessidade de ser liberado, ou é autoreleased? Nem. @ "" - cordas são de classe NSConstantString ?, e assim actuar como átomos no cicio; eles ficam em torno. Ou seja, se você usar @ "vaca" em dois locais distintos no seu código, eles serão referenciando o mesmo objeto. Eu não acho que -release ou -autorelease faz nada para nenhum deles.
Se eu tiver "cópia" na propriedade, porém, não deveria copiar o conteúdo da memória de destino em nova memória com uma reter contar de 1? Parece o atributo cópia não faz nada neste caso?
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char *cstr = "this is a c string";
NSString *str = [[NSString alloc] initWithUTF8String:cstr];
NSLog(@"rc1: %d", [str retainCount]);
[pool drain];
return 0;
}
Se você executar o código acima, ele irá exibir uma contagem de 1
reterEm Cacau, muitos objetos imutáveis ??simplesmente manter-se quando você pedir uma cópia da mesma zona. Se o objeto não está garantido para a mudança (ou seja, a sua imutabilidade), em seguida, uma cópia exata é redundante.
Em Objective-C, a classe string constante é separado para a aula NSString
de cacau, embora possa ser uma subclasse de NSString
(Eu não estou muito certo). Esta classe string constante pode substituir métodos de NSObject
como retain
, release
e dealloc
para que eles não fazem nada, e também substituir retainCount
para que ele sempre retorna o mesmo número, UINT_MAX
ou assim. Isso ocorre porque um string constante Objective-C é criada na memória estática. Ele deve ter o comportamento geral global de um objeto Cocoa (ao usar cacau), de modo que ele pode ser adicionado a matrizes, usadas como chaves para um dicionário etc, exceto no que diz respeito à sua gestão de memória, uma vez que foi alocada de forma diferente.
Disclaimer:. Eu realmente não sei o que estou falando