2011-02-03 23 views
5

¿Hay alguna forma de que emule el comportamiento de la categoría para una clase con respecto a sus variables de instancia, no a los métodos?Extensión similar a una categoría para las variables de instancia

Tengo un ClassA, y quiero mantener su nombre después de extenderlo con los nuevos métodos Y ivars de otro cllass (ClassB). Por supuesto, puedo heredar ClassA, pero la clase resultante tendrá un nombre diferente.

Para la adición de métodos, no es un problema - la categoría sería una buena solución.

ACTUALIZACIÓN:ClassA utilizado como propietario archivo para un XI ter, y estos campos para ser extendidas son IBOutlet s. Entonces los necesito en la fase de construcción.

+0

¿Qué tiene de malo tener un nuevo nombre? Si intentas hackear la herencia de clases, ¡probablemente haya una forma mejor de hacer lo que intentas hacer! – deanWombourne

+0

@deanWombourne: por favor, vea la pregunta actualizada. A veces, hay situaciones en las que necesitamos un enfoque inusual. –

Respuesta

3

He investigado esta pregunta jugando a associative references (gracias a Ole), con métodos variables estáticos, métodos swizzling, y finalmente llego a esta solución simple (sin tiempo de ejecución). Simplemente uso la clase "categorizada" solo para devolver un puntero a una clase derivada, que por supuesto puede contener ivars adicionales. Al hacerlo, obtengo un beneficio inesperado: puedo llamar a los métodos de clase super, lo cual es imposible cuando se extiende a través de categorías.

Ejemplo de una extensión de clase (probado):

ClassA + ClassB.h

@protocol _ClassB_Protocol 
    @optional // to avoid warnings 
- (IBAction) onClick:(id)sender; 
    @property (nonatomic, retain) IBOutlet UIButton *aButton; 
@end 

@interface ClassA (_ClassA_Category) <_ClassB_Protocol> 
@end 

@interface ClassB: ClassA <_ClassB_Protocol> { 
    UIButton *aButton; // _ivar_ to add 
} 
@end 

ClassA + ClassB.m

@implementation ClassA (_ClassA_Category) 
// this will be called first on [ClassA alloc] or [ClassA allocWithZone:(NSZone *)zone] 
+(id) alloc { 
    if ([self isEqual: [ClassA class]]) { 
     return [ClassB alloc]; 
    } else { 
     return [super alloc]; 
    } 
} 
@end 


@implementation ClassB: ClassA 

@synthesize aButton; 

-(void) dealloc { 
    [aButton release]; 

    [super dealloc]; // this is impossible for an ordinary category 
} 

- (void) onClick:(id)sender { 
    // some code here 
} 

@end 

Ahora tenemos en el mismo tiempo:

  • ClassB "se extiende" ClassA (categoría de forma);
  • ClassB hereda ClassA (ClassB puede llamar a ClassA métodos);
  • ClassB se puede acceder a través ClassA nombre (categoría de forma)
6

Dado que el iPhone utiliza el tiempo de ejecución de Objective-C moderno, puede usar associative references para agregar datos a instancias sin tener que declarar variables de instancia. Consulte la documentación para objc_setAssociatedObject etc.

Si ajusta las llamadas al tiempo de ejecución en los métodos de acceso estándar, será muy fácil de usar.

+0

+1 para solución de nivel de tiempo de ejecución. Sin embargo, utilizo 'ClassA' como ** propietario de archivo ** para un XIB, y estos campos son' IBOutlets'. Entonces, los necesito en la fase de construcción. Perdón por no haber especificado este detalle. –

+0

¿Qué sucede si declara '@property (retener) IBOutlet id myVar;' en una categoría? ¿Aparece en IB? –

+0

Sí. ¡Gran sugerencia! Voy a probar un caso simple usando referencias asociativas. –

2

pongo el ejemplo de Martin en una aplicación trivial reemplazando claseA con NSData, ClassB con XXData y onClick con getIvar, y lo invocó (Mac OS X 10.6 .6, Xcode 4 Final) con:

NSData * data = [NSData data]; 
NSLog(@"%@", [data getIvar]); 

falla con "- [NSConcreteData getIvar]: Selector no reconocido enviado a la instancia" ..

falla porque "alloc" en la categoría NSData (que devuelve el puntero a la clase derivada) no es invocado por el código anterior. Si, en cambio, se llama explícitamente "alloc", como en:

NSData * data = [[NSData alloc] init]; 
NSLog(@"%@", [data getIvar]); 

, entonces todo está bien.

+0

Sí, hay una excepción para este método. Debe tener en cuenta cuando aplique esta técnica a Class Cluster's. De esta categoría hay algunas clases integradas de Cocoa como: NSData, NSArray, etc. –

Cuestiones relacionadas