2010-05-14 14 views
10

que tienen una porción de código de Objective-C que se parece a lo siguiente:¿Cómo puedo solucionar esta advertencia de clang: "El objeto con +0 retendrá los conteos devueltos al llamador donde se espera el recuento de retención de +1 (poseer)?"

- (NSString *)copyData:(NSData *)data 
{ 
    NSString *path = [[[self outputDirectory] stringByAppendingPathComponent:@"archive"] stringByAppendingPathExtension:@"zip"]; 
    NSLog(@"Copying data to %@", path); 
    [data writeToFile:path atomically:NO]; 
    return path; 
} 

El código se llama desde un inicializador que tiene este aspecto:

- (id)initWithData:(NSData *)data 
{ 
    if ((self = [super init]) != nil) { 
     NSString *path = [self copyData:data];  // Line 41 (referenced in warning, shown below) 
     return [self initWithContentsOfFile:path]; 
    } 
    return self; 
} 

Al ejecutar el analizador estático sonido metálico, consigo las siguientes advertencias para el path variables:

potenciales de fuga de un objeto asignado en la línea 41 y se almacena en el 'camino'

objeto con +0 retener los recuentos volvió a llamante, donde 1 (propietaria) se espera retener recuento

estoy confundido. Mi entendimiento es que stringByAppendingPathComponent debería devolver una cadena autoreleased, por lo que debe tener una red retener cuenta de 0. (Obviamente yo no quiero para retenerlo.)

He intentado alterar copyData: para volver lo siguiente, pero no se deshizo de la advertencia:

return [[path retain] autorelease]; 

¿Cuál es el problema con esta advertencia?

Respuesta

15

Sospecho que solo está notando un método con el prefijo copy y marcando eso como algo que debe devolver algo que posee la persona que llama, porque cree que está siguiendo las convenciones de nomenclatura de Cocoa.

En su caso, por supuesto, se está refiriendo a los archivos y otras cosas, por lo que es una advertencia ignorable. Si cambias el nombre de tu método, a algo como saveData:, apuesto a que la advertencia desaparecerá.

4

Dado que el método tiene el nombre copy en él, el analizador espera que el objeto devuelto tenga un recuento de retención +1, de acuerdo con Memory Management Guide.

4

No, eso es incorrecto; a menos que el método contenga "alloc", "copy", "new" o alguna de las otras palabras clave que implican que el objeto será propiedad del invocador, el método devuelve un objeto liberado automáticamente o gestionado de otra manera, por lo que stringByAppendingPathComponent está devolviendo una cadena autorretratada .

Además de eso, su método "copyData", contiene la palabra "copiar", lo que implica que el resultado debe ser propiedad (y liberado) por la persona que llama. Sin embargo, el resultado que devolvió se ha soltado automáticamente, de ahí el mensaje de error que le está dando. Si quiere corregir el error, no lo suelte automáticamente. Es decir:

return [path retain] 

Por supuesto, eso implica que las personas que llaman de su función necesitan liberarlo. Alternativamente, puede cambiar el nombre de su función para que cumpla con las pautas de administración de memoria.

El nombre "copyData", en mi humilde opinión, no es intuitivo de todos modos. Sugeriría que cambie el nombre de su función a "pathToSavedDataWithData" o similar. Algo que dice lo que realmente está haciendo.

9

Además, para las veces que realmente desea nombrar un método con 'copia' o algo así porque independientemente de las pautas de administración de la memoria Cocoa, copiar es el mejor nombre para el método, puede anotar la declaración del método con NS_RETURNS_NOT_RETAINED y luego Clang no te dará una advertencia. Por lo tanto:

// Copies data from data to string; does not follow the copy rule 
- (NSString*)copyData:(NSData*)data NS_RETURNS_NOT_RETAINED; 
+1

¡Esta respuesta acaba de eliminar tantas advertencias incorrectas de mi proyecto! –

0

Voy a tomar una puñalada en esto y supongo que no puedes encontrar el mismo mensaje de error exacto, si es o no el nombre de su rutina comenzó con "copia ..." o no . Acabo de terminar en un escenario similar y "copiar" no era parte del nombre de la rutina que estaba llamando. Clang estaba dando el mensaje de error simplemente porque estaba devolviendo un objeto liberado automáticamente, una situación peligrosa. Haciendo el

return [path retain] 

truco al final como lo recomendó Michael se encargó del problema.

+0

¡Vaya! ¿Puedo comentar mi propia respuesta? Resulta que el nombre de mi rutina comenzó con "nuevo ...", así que parece que estaba un poco apresurado. Lo sé mejor ahora. :-) – hkatz

Cuestiones relacionadas