2008-12-31 8 views
5

tengo la siguiente clase de ejemplo:Objetivo C NSString * propiedad de retener rareza recuento

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 produce el siguiente 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 

I am call ing lo como:

Test *test = [[Test alloc] initWithValue:@"some text"]; 

¿No debería el valor tener un conteo de retención de 1? ¿Qué me estoy perdiendo?

Gracias por su ayuda.

Respuesta

3

Tiene una referencia a una cadena inmutable. La asignación no necesita copiar el valor (los datos de cadena) ya que es inmutable. Si realiza una operación mutable, como value = [newValue uppercaseString], debe copiar los bits en valor y el conteo de retención del valor incrementado.

+1

Esto realmente no aborda los problemas fundamentales con el código del póster original: no está siguiendo las reglas de administración de memoria, y está asignando directamente a una variable de instancia en lugar de pasar por la propiedad. –

10

Usted está pasando en una cadena literal. El compilador probablemente lo asigna a la memoria estática y establece el recuento de retenciones al máximo valor posible.

Pruebe una cadena asignada dinámicamente y vea qué ocurre.

NSString* string = [[NSString alloc] initWithString: @"some text"]; 
Test* test = [[Test alloc] initWithValue: string]; 
+0

¿Lo está asignando en la memoria estática a pesar de que uso el atributo copiar en la propiedad? –

+0

Si desea usar la propiedad, debe decir "self.value = whatever" en lugar de simplemente "value = whatever", que simplemente asigna la variable de instancia. –

+2

hecho .. mismo error. También intenté usar el código dinámico de cadena de arriba. –

3

Está pasando una constante de cadena, que en realidad no se puede desasignar. Creo que 2147483647 es probablemente UINT_MAX, lo que básicamente significa que el objeto no puede ser liberado.

+0

¿el atributo copiar no hace una nueva copia no en la memoria estática? –

+0

¿Cuál sería el objetivo de eso? No puede cambiar el valor, por lo que también puede apuntar a la memoria estática. Tal vez valga la pena intentar cambiar el tipo a NSMutableString para ver si obtienes el mismo comportamiento. –

+0

es posible para una copia para realmente retener el original cuando el original es inmutable, por lo que una copia se garantizará idéntica. –

3

creo que quiere hacer esto:

self.value = newValue; 

que invocará el colocador propiedad y causar que se produzca la copia. "value = newValue" simplemente asigna un valor de puntero a la variable de instancia.

+0

gracias, .. hice el cambio ...sigue siendo el mismo error –

0

hmm .. nos estamos acercando.

parece que mantener el recuento de nuevoValor también es 2147483647.

He intentado asignar dinámicamente la cadena en lugar de mantener los mismos resultados del conteo.

He encontrado un artículo útil aquí: http://www.cocoadev.com/index.pl?NSString

TLC:

¿El NSString devueltos por @ "" tiene que ser puesto en libertad, o es autoreleased? Ninguno. @ "" - las cadenas son de clase NSConstantString ?, y por lo tanto actúan como átomos en lisp; ellos se quedan. Es decir, si usa @ "cow" en dos lugares separados en su código, harán referencia al mismo objeto. No creo -release o -autore hace nada con ninguno de ellos.

Si tengo "copiar" en la propiedad, ¿no debería copiar el contenido de la memoria de destino en la memoria nueva con un conteo de retención de 1? Parecería que el atributo de copia no hace nada en este caso?

+0

Esto es lo que entiendo: cuando haces una "copia" en un objeto inmutable, en realidad solo lo conservas. Hacer una copia de una cadena mutable (u otro objeto mutable) realmente lo copia. No te obsesiones demasiado con todo el asunto de la retención. Si balanceas cada alloc con liberación, lo harás bien. –

21

No mires los conteos de retención. No son útiles y solo te inducirán a error: no puedes estar seguro de que nada más está reteniendo un objeto, que un objeto que obtienes de algún lado no se comparte.

En su lugar, concéntrese en propiedad del objeto y siga el Cocoa memory management rules a la carta. De esa forma, la administración de su memoria será correcta sin importar las optimizaciones que Cocoa pueda estar haciendo detrás de las escenas por usted. (Por ejemplo, la aplicación de -copy tan solo -retain para objetos inmutables.)

Por otra parte, es fundamental a entender la diferencia entre propiedades de los objetos y variables de instancia dentro de sus objetos. En el código de su pregunta, está asignando un valor a una variable de instancia. Esa variable de instancia es solo eso: una variable. Asignarlo se comportará como cualquier otra asignación de variable. Para utilizar la propiedad, debe utilizar la sintaxis con punto o la sintaxis soporte para invocar realidad método setter de la propiedad:

self.value = newValue;  // this is exactly equivalent to the next line 
[self setValue:newValue]; // this is exactly equivalent to the previous line 

el código generado para la sintaxis con punto y la sintaxis de soporte es idéntico, y tampoco se accede a la variable de instancia directamente.

0
#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; 
} 

Si ejecuta el código anterior, se mostrará una cuenta de retención de 1

0

En cacao, muchos objetos inmutables simplemente mantener a sí mismos cuando se pide una copia de la misma zona. Si se garantiza que el objeto no cambiará (es decir, su inmutabilidad), entonces un duplicado exacto es redundante.

En Objective-C, la clase de cadena constante está separada de la clase NSString de Cocoa, aunque puede ser una subclase de NSString (no estoy muy seguro). Esta clase de cadena constante puede anular los métodos NSObject como retain, release y dealloc para que no hagan nada, y también anular retainCount para que siempre devuelva el mismo número, UINT_MAX más o menos. Esto se debe a que una cadena constante de Objective-C se crea en la memoria estática. Debe tener el comportamiento general general de un objeto Cocoa (cuando se usa Cocoa) para que se pueda agregar a matrices, usar como claves para un diccionario, etc., excepto en lo que respecta a su administración de memoria, ya que se asignó de manera diferente.

Descargo de responsabilidad: en realidad no sé de lo que estoy hablando.

Cuestiones relacionadas