objective c - libros - ¿Cómo se maneja la liberación para las propiedades de retención @synthesized?
ebook gratis (4)
Tengo algunas preguntas sobre las propiedades sintetizadas en Objective-C. La lista completa sigue, pero la pregunta básica es esta: ¿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?
Nota: Decidí no publicar estas preguntas como individuales porque están muy relacionadas y porque hay un puñado de preguntas existentes que abordan los problemas individuales sin llegar realmente al meollo del asunto.
Preguntas algo similares:
- ¿La propiedad retener necesita una versión?
- ¿Cuál es la diferencia entre propiedad y sintetizar?
- Pregunta sobre retener atributo con propiedad y sintetizar
Configuración: considere 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, asumo que el name
lanzará automáticamente cada vez que se suelte 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 elijo escribir mi propio método dealloc
para esta clase, y omito una llamada a [name release]
, ¿se filtrará?
@implementation Person
@synthesize name;
- (void)dealloc { [super dealloc]; }
@end
Pregunta n. ° 3: si elijo escribir mi propio método dealloc
para esta clase, e dealloc
una llamada a [name release]
, ¿dará como resultado una versión doble, ya que @synthesize
ya se ha ocupado de mí?
@implementation Person
@synthesize name;
- (void)dealloc { [name release]; [super dealloc]; }
@end
Pregunta # 4: Si elijo escribir mi propio acceso a la propiedad para esta clase, pero no escribo mi propio método dealloc
, ¿se dealloc
name
?
@implementation Person
@dynamic name;
- (void)setName:(NSString *)newName
{
[newName retain];
[name release];
name = newName;
}
@end
Pregunta n. ° 5: tengo la sensación (basada en la experiencia) de que ninguno de los escenarios anteriores dará como resultado filtraciones o dobles lanzamientos, ya que el lenguaje ha sido diseñado para evitarlos. 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? ¿Qué pasaría si tuviera que hacer lo siguiente? (Tenga en cuenta que este es un ejemplo ridículo, solo para ilustrar mi punto):
void Cleanup(id object) { [object release]; }
@implementation Person
@synthesize name;
- (void)dealloc { Cleanup(name); }
@end
¿ dealloc
al compilador para que agregue otro [name release]
al método dealloc
?
De la documentación de Objective-C en propiedades :
dealloc
Las propiedades declaradas toman fundamentalmente el lugar de las declaraciones de métodos de acceso; cuando sintetiza una propiedad, el compilador solo crea los métodos de acceso ausentes. No hay interacción directa con el método dealloc: las propiedades no se liberan automáticamente. Las propiedades declaradas, sin embargo, proporcionan una forma útil de verificar la implementación de su método dealloc: puede buscar todas las declaraciones de propiedad en su archivo de encabezado y asegurarse de que las propiedades del objeto que no están marcadas assign se liberen, y las que se marcan asignar son no publicado.
Esto esencialmente responde todas tus preguntas.
Hay algo más que vale la pena saber: si tiene una propiedad sintetizada, establecer esa propiedad en cero (usando la sintaxis de punto, por supuesto) liberará el ivar por usted.
La regla simple y general: si asigna, retiene o copia un objeto, USTED tiene que liberarlo.
Cuando utiliza la configuración semántica del colocador de retain
en una instrucción @synthesize
, le está pidiendo al compilador que @synthesize
para usted un configurador que llama retain
en el objeto. Nada más y nada menos. Y como está reteniendo ese objeto (aunque sea a través de un código autogenerado mágicamente), tiene que liberarlo, y dónde liberarlo está en -(void)dealloc
.
Q1:
No. @synthesize
no modifica el -dealloc
por ti. Tienes que- -release
el name
tú mismo.
Q2:
Sí, se filtrará. La misma razón que Q1.
Q3:
No, no será de doble lanzamiento. La misma razón que Q1.
Q4:
Sí, se filtrará. La misma razón que Q1.
Q5:
No, no será de doble lanzamiento. La misma razón que Q1.
Puede verificar esto usted mismo -retain
-dealloc
y -dealloc
y -dealloc
para informar lo que está sucediendo.
#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 -retainCount
de x
es 1, por lo que hay una fuga, y en Q3 y Q5, el último -retainCount
es 0 y se llama -dealloc
, por lo que no hay pérdida.