2009-08-20 6 views
6

Quiero activar algún código cuando se accede y cambia una propiedad. Yo uso @property y @synthesize en mi código para mis ivars. Las propiedades se conservan, por lo que me gustaría mantener ese material de gestión de memoria generado automáticamente por @synthesize.¿Cómo proporcionar una implementación personalizada adicional de métodos de acceso cuando se usa @synthesize?

Sin embargo, supongo que @synthesize le dice al compilador que genere el código de los métodos de acceso justo donde @synthesize is, por lo que la mayoría de los casos en la parte superior del código, ¿verdad?

Y cuando tengo una propiedad foo, obtengo los métodos -setFoo y -foo. ¿Podría entonces hacer un método como este para ejecutar un código más personalizado cuando se cambia una propiedad?

-(void)setFoo { 
    // custom stuff 
} 

Eso es un problema. ¿Cómo ejecutar el primero? No me gustaría tener un nombre diferente aquí. ¿Existe alguna manera de permitir que la directiva @synthesize cree otros nombres para los métodos getter y setter, que luego llamo fácilmente? ¿Y aún así podría usar la sintaxis de puntos para acceder a ellos?

Respuesta

5

Puede usar @property y @synthesize como lo haría normalmente, pero proporcione un setter o getter personalizado (o ambos) y se usarán en su lugar. Normalmente haré algo como esto:

// Override the setter 
- (void)setName:(NSString *)aName 
{ 
    if (name == aName) 
     return; 

    [name release]; 
    name = [aName retain]; 

    //custom code here 
} 

Cuando uso la propiedad set, invocará mi método personalizado. Sin embargo, el get aún se sintetizará.

+1

FYI, su setter de ejemplo tiene un error, porque llamarlo dos veces con el mismo objeto puede causar que dicho objeto se desasigne antes de retenerlo. No es realmente un gran problema, pero ilustra cuán difícil puede ser para que todo salga bien. –

+0

No estoy seguro de seguir, ¿podría explicar cómo debe escribirse en su lugar (no es que no le creo, me gustaría saber cómo hacerlo correctamente). Gracias :) – jbrennan

+1

Oh, nvm Veo el problema, lo actualizaré para reflejar los cambios. – jbrennan

1

Si proporciona una implementación para los instaladores o captadores, usará eso en lugar de la implementación generada. No es difícil implementar el aspecto de "retención" de los getters y setters generados por el compilador cuando se sintetizan, por lo que puedes escribir tus propios getters y setters, diría yo e ir con eso.

-2

Sí, en su declaración @property, puede especificar los métodos getter y setter.

@property (readwrite,getter=privateGetFoo,setter=privateSetFoo:) NSObject * foo; 

En sus foo y setFoo: métodos, llamar [self privateGetFoo] o [self privateSetFoo:f] entonces su código personalizado.

El objeto también puede establecer un observador en sí mismo con addObserver:forKeyPath:options:context:.

Dicho esto, no creo que ninguna de estas formas sean muy limpias para hacer las cosas. Es mejor escribir su propio getter/setter como otros han sugerido.

+0

Usted dijo: "En su foo y setFoo: métodos ..." Mientras [obj setFoo: x] y [obj foo] están disponibles, es importante tener en cuenta que debido a la propiedad modificada, obj.foo no estar disponible para escribir, y deberá usar obj.setFoo = x. Esta no es la forma en que @property normalmente lo hace, donde obj.foo se usa tanto para leer como para escribir. – mahboudz

+0

Entonces object.foo es equivalente a [object privateFoo], lo cual frustra el propósito completo de usar propiedades. –

0

Una solución extravagante es crear una súper clase abstracta que te da la síntesis de propiedad normal. Luego crea una subclase concreta que realmente usarás, y que simplemente implementa y anula el método (misma firma) y llama a super para hacer la configuración real. Esto le permite hacer lo que quiera antes o después de la llamada a la implementación de super.

Ejemplo:

@interface ALTOClassA : NSObject 


@property NSString *catName; 

@end 

Nada más se necesita en el .m más allá del archivo apagó para esta prueba.

Crear la subclase, nada necesitaba especialmente en el @interface

#import "ALTOClassA.h" 

@interface ALTOClassAJunior : ALTOClassA 

@end 

En el @implementation hacemos nuestro anulación.

#import "ALTOClassAJunior.h" 

@implementation ALTOClassAJunior 


- (void)setCatName:(NSString*)aCatName { 
    NSLog(@"%@",NSStringFromSelector(_cmd)); 
    [super setCatName:aCatName]; 
    NSLog(@"after super: self.catName %@", self.catName); 
} 
@end 

En uso:

ALTOClassAJunior *aCAJ = [ALTOClassAJunior new]; 
NSLog(@"aCAS.catName %@", aCAJ.catName); 

NSLog(@"set it to George."); 

[aCAJ setCatName:@"George"]; 

NSLog(@"aCAS.catName %@", aCAJ.catName); 

Esto le permite aprovechar el código autogenerado, y lo siguen haciendo las cosas que quiere hacer con su clase. Resumen Super Class a menudo es una solución útil para muchas cosas.

Cuestiones relacionadas