64

Tengo algunas preguntas sobre las propiedades sintetizadas en Objective-C. La lista completa sigue, pero la pregunta básica es la siguiente: ¿Cómo garantiza el compilador que los ivars para las propiedades sintetizadas se lanzan correctamente, aunque mi código puede incluir o no métodos de publicación en dealloc?¿Cómo se maneja la liberación para las propiedades de retención @synthesized?

Nota: decidí no publicar estas preguntas como individuales, ya que están tan estrechamente relacionados y porque hay un puñado de preguntas existentes que contacto sobre las cuestiones individuales sin realmente entrar en el meollo de la cuestión.

preguntas algo similar:


Configuración: considerar una clase con una sola propiedad:

@interface Person : NSObject 
{ 
    NSString * name; 
} 
@property (nonatomic, retain) name; 
@end 

Pregunta # 1: El caso muy básico:

@implementation Person 
@synthesize name; 
@end 

Con esta configuración, supongo que name serán liberados automáticamente cada vez que se libera un objeto Person. En mi opinión, el compilador simplemente inserta [name release] en el método dealloc como si yo mismo lo hubiera escrito. ¿Es eso correcto?


Pregunta # 2: Si decido a escribir mi propio método dealloc para esta clase, y omito una llamada a [name release], habrá que escape?

@implementation Person 
@synthesize name; 
- (void)dealloc { [super dealloc]; } 
@end 

Pregunta # 3: Si decido a escribir mi propio método dealloc para esta clase, y yo incluyo una llamada a [name release], hará que se traducen en una doble versión, ya que @synthesize ya se ha ocupado de eso por mí?

@implementation Person 
@synthesize name; 
- (void)dealloc { [name release]; [super dealloc]; } 
@end 

Pregunta # 4: Si decido a escribir mi propio acceso a la propiedad de esta clase, pero No escribir mi propio método dealloc, se name ser filtrada?

@implementation Person 
@dynamic name; 
- (void)setName:(NSString *)newName 
{ 
    [newName retain]; 
    [name release]; 
    name = newName; 
} 
@end 

Pregunta # 5: tengo la sensación (basado en la experiencia) que ninguno de los escenarios anteriores dará lugar a fugas o dobles comunicados, ya que el lenguaje ha sido diseñado para evitar ellos. Eso, por supuesto, plantea la pregunta de "¿cómo?". ¿Es el compilador simplemente lo suficientemente inteligente como para realizar un seguimiento de todos los casos posibles? ¿Y si tuviera que hacer lo siguiente (tenga en cuenta que este es un ejemplo absurdo, sólo significaba para ilustrar mi punto):

void Cleanup(id object) { [object release]; } 

@implementation Person 
@synthesize name; 
- (void)dealloc { Cleanup(name); } 
@end 

Ojalá engañar al compilador en la adición de otra [name release] al método dealloc?

Respuesta

57

P1:

@synthesize no modifica el -dealloc para usted. Tienes que -release el name tú mismo.

P2:

sí, va a tener fugas. La misma razón que Q1.

P3:

No, no lo hará de doble liberación. La misma razón que Q1.

P4:

sí, va a tener fugas. La misma razón que Q1.

Q5:

No, no lo hará de doble liberación. La misma razón que Q1.


Puede verificar esto anulando -retain y -release-dealloc y para informar de lo que está pasando.

#import <Foundation/Foundation.h> 

@interface X : NSObject {} 
@end 
@implementation X 
-(oneway void)release { 
     NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1); 
     [super release]; 
} 
-(id)retain { 
     NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1); 
     return [super retain]; 
} 
-(void)dealloc { 
     NSLog(@"Dealloc %p", self); 
     [super dealloc]; 
} 
@end 

@interface Y : NSObject { 
     X* x; 
} 
@property (nonatomic, retain) X* x; 
@end 
@implementation Y 
@synthesize x; 
- (void)dealloc { [x release]; [super dealloc]; } 
@end 

int main() { 
     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
     Y* y = [[Y alloc] init]; 
     X* x = [[X alloc] init]; 
     y.x = x; 
     [y release]; 
     [x release]; 
     [pool drain];              
     return 0; 
} 

En Q1, Q2 y Q4, el último -retainCount de x es 1, por lo que existe una fuga, y en la Q3 y Q5 el último -retainCount es 0 y -dealloc se llama, así que no hay fugas.

+2

Gracias por la respuesta detallada. ¡Me alegro de haber preguntado! –

+0

¡Muy bien explicado! –

17

De los Objective-C documentation on properties:

dealloc

propiedades declaradas fundamentalmente tomar el lugar de método de acceso declaraciones; cuando sintetiza una propiedad , el compilador solo crea cualquier método de acceso ausente. No es ninguna interacción directa con el dealloc método-propiedades no son liberados automáticamente para usted. propiedades declaradas hacen, sin embargo, proporcionan una forma útil para cotejar la aplicación de su método de dealloc : se puede buscar todos los declaraciones de bienes en el archivo de cabecera y asegúrese de que ese objeto propiedades no marcados asigna son liberado, y los marcados asignar son no lanzados.

Esto esencialmente responde a todas sus preguntas.

+0

+1 Gracias por el enlace. Eso sin duda llega al corazón del asunto. –

8

La regla simple y general: si asigna, retiene o copia un objeto, debe liberarlo.

Cuando se utiliza la configuración semántica retain colocador en un comunicado @synthesize, usted está pidiendo el compilador construir para que un regulador que llama retain en el objeto. Nada más y nada menos. Y como está conservando ese objeto (aunque sea a través de un código mágico autogenerado), debe liberarlo y dónde liberarlo está en -(void)dealloc.

+4

+1 Esa es una regla excelente (y frecuentemente referenciada). Muchas personas (incluyéndome, cuando hice esta pregunta) no se dan cuenta de que especificar "retener" o "copiar" en una declaración de propiedad todavía califica. Creo que el problema radica en la fraseología: "¿Retenía * I * el valor? No, el código automático del compilador lo hizo por mí. Vaya". –

+1

Unos meses después de publicar esta respuesta, publiqué una aún mejor, aquí: http://stackoverflow.com/questions/5122786/iphone-objective-c-should-this-value-be-released/5122821#5122821 Tiene una buena mnemotécnica. Ve a ver. –

+0

cosas buenas. ¡Espero que entienda! –

2

Algo más que vale la pena saber: si tiene una propiedad sintetizada, establecer esa propiedad en cero (usando la sintaxis de puntos, por supuesto) liberará el ivar por usted.

Cuestiones relacionadas