2012-05-26 18 views
7

Decir que tengo esta claseCrear subclase con diferentes propiedades subclase

@interface CustomClass : NSObject 

@property (nonatomic, strong) NSArray * nicestArrayEver; 

@end 

Y quiero crear una subclase de CustomClass, pero aquí está la trampa

@interface ASubClassCustomClass : CustomClass 

@property (nonatomic, strong) NSMutableArray * nicestArrayEver; 

@end 

La cuestión como se puede imaginar es que cuando inicializo ASubClassCustomClass y llamo a este superinicializador (ya que hay otras propiedades requeridas) se crea el incatable nicestArrayEver ... ¿cómo puedo evitar su creación para poder establecer el mutable?

Nota: Esto es solo un ejemplo, la implementación real requiere una subclase pesada para crear y realmente personalizada (no es una NSArray).

Respuesta

5

Puede hacer que funcione, mediante el uso de diferentes variables de respaldo, al sintetizar que tiene este aspecto: @synthesize nicestArrayEver = nicestArrayEverSubClass_;

#import <Foundation/Foundation.h> 

@interface CustomClass : NSObject 

@property (nonatomic, strong) NSArray * nicestArrayEver; 

@end 

@implementation CustomClass 
@synthesize nicestArrayEver ; 

-(id)init 
{ 
    if (self = [super init]) { 
     nicestArrayEver = [[NSArray alloc] init]; 
    } 
    return self; 
} 
@end 

@interface ASubClassCustomClass : CustomClass 

@property (nonatomic, strong) NSMutableArray * nicestArrayEver; 

@end 

@implementation ASubClassCustomClass 
@synthesize nicestArrayEver = nicestArrayEverSubClass_; 

-(id)init{ 
    if (self = [super init]) { 
     nicestArrayEverSubClass_ = [[NSMutableArray alloc] init]; 
    } 
    return self; 
} 
@end 



int main(int argc, const char * argv[]) 
{ 

    @autoreleasepool { 

     CustomClass *c1 = [[[CustomClass alloc] init] autorelease]; 
     ASubClassCustomClass *c2 = [[[ASubClassCustomClass alloc] init] autorelease]; 

     NSLog(@"%@", NSStringFromClass([[c1 nicestArrayEver] class])); 
     NSLog(@"%@", NSStringFromClass([[c2 nicestArrayEver] class])); 

    } 
    return 0; 
} 

salida

2012-05-27 01:59:16.221 NicestArray[2312:403] __NSArrayI 
2012-05-27 01:59:16.225 NicestArray[2312:403] __NSArrayM 

Otro enfoque podría ser tener 2 métodos init en la clase base, uno, que instanciará la propiedad y otro, que no lo hará, pero deja esa tarea para el niño c muchacha: esto le impedirá crear objetos caros solo para tirarlos.
Ahora la clase base podría ser instanciada directamente con el segundo init y pasar a un estado falso. Puede evitar esto marcando el tipo de clase propia con isMemberOfClass:, y lanzar un error, si el tipo de clase es la clase base.

@interface CustomClass : NSObject 

@property (nonatomic, strong) NSArray * nicestArrayEver; 
-(id)initWithoutArray; 
@end 

@implementation CustomClass 
@synthesize nicestArrayEver ; 

-(id) initWithoutArray 
{ 
    if (self = [super init]) { 
     if ([self isMemberOfClass:[CustomClass class]]) { 
      [NSException raise:@"AbstractMethodCall" format:@"%@ should be called only from Subclasses of %@", NSStringFromSelector(_cmd), NSStringFromClass([self class])]; 
     } 
    } 
    return self; 
} 


-(id)init 
{ 
    if (self = [super init]) { 
     nicestArrayEver = [[NSArray alloc] init]; 
    } 
    return self; 
} 
@end 

@interface ASubClassCustomClass : CustomClass 

@property (nonatomic, strong) NSMutableArray * nicestArrayEver; 

@end 

@implementation ASubClassCustomClass 
@synthesize nicestArrayEver = nicestArrayEverSubClass_; 

-(id)init{ 
    if (self = [super initWithoutArray]) { 
     nicestArrayEverSubClass_ = [[NSMutableArray alloc] init]; 
    } 
    return self; 
} 

@end 



int main(int argc, const char * argv[]) 
{ 

    @autoreleasepool { 

     CustomClass *c1 = [[[CustomClass alloc] init] autorelease]; 
     ASubClassCustomClass *c2 = [[[ASubClassCustomClass alloc] init] autorelease]; 

     NSLog(@"%@", NSStringFromClass([[c1 nicestArrayEver] class])); 
     NSLog(@"%@", NSStringFromClass([[c2 nicestArrayEver] class])); 

     //this works, as it is the subclass 
     ASubClassCustomClass *shouldWork = [[[ASubClassCustomClass alloc] init] autorelease]; 

     // ouch! 
     CustomClass *shouldCrash = [[[CustomClass alloc] initWithoutArray] autorelease]; 

    } 
    return 0; 
} 
+1

+1 por responder a la pregunta y por haber demostrado que estoy equivocado. :) –

-1

Realmente no se puede hacer eso. Simplemente cree CustomClass con NSMutableArray. Puede crearlos como tipo id y marcar isKindOfClass:, pero eso es solo una tarea que no es realmente necesario.

realidad, hay sólo dos razones por las que pude ver como hacer lo que preguntas:

  1. para evitar la sobrecarga adicional de NSMutableArray
  2. Para evitar CustomClass de modificar el contenido de la matriz a menos que sea a ASubClassCustomClass.

Si bien estos son buenos objetivos, diría que en este caso vale la pena simplificar un poco.

+0

Josh, por favor vea la Nota que acabo de agregar. Estoy de acuerdo con usted, si fuera un NSArray, pero en este caso, no es, y es pesado. –

+0

De cualquier manera, todavía estás en el mismo barco. Puede valer la pena volver a examinar su diseño. Si un niño tiene un tipo de información diferente a su superclase, probablemente valga la pena almacenarla en una variable diferente. Si lo desea, podría crear un método de clase que devuelva la variable adecuada y anularla en su subclase. –

+0

De hecho, es absolutamente posible tener una propiedad con el mismo nombre pero un tipo diferente en una subclase. La única pega es que (a menos que se haya cambiado la visibilidad del ivar de la superclase), el respaldo ivar debe tener un nombre diferente. Ver http://stackoverflow.com/a/10690692/ o la respuesta de vikingosegundo a esta misma pregunta. –

1

no veo la razón por la que se quiere hacer eso, pero yo le aconsejaría que lo haga de la siguiente manera: en la subclase declarar una propiedad NSMutableArray separado (vamos a llamarlo nicestMutableArrayEver) y anular el captador para su superclase NSArray propiedad para devolver la instancia mutableArray:

- (NSArray *)nicestArrayEver { 
    return [self nicestMutableArrayEver]; 
} 

de esta manera, se podría volver a su mutableArray siempre se hace referencia a la propiedad de la superclase.

Mejor,

+0

No veo, por qué alguien no quiere hacerlo. Esta relación entre CustomClass y ASubClassCustomClass es una especialización de un caso común a uno más especial: un patrón muy típico en el diseño orientado a objetos. Tenga en cuenta también que, con su enfoque, los moldes se necesitarán constantemente y también se cierran las advertencias del compilador. – vikingosegundo

1

Las propiedades casi nunca deben tener tipo mutable.Si lo hacen, entonces una persona que llama puede obtener el puntero y mutar las propiedades del objeto detrás de su espalda. Si una propiedad debe ser externamente mutable, debería ser a través de métodos de mutación.

Recuerde que las propiedades definen la interfaz, no la implementación. @synthesize puede crear implementación a partir de la declaración de propiedad, pero si eso haría lo incorrecto, no debería usarlo.

Por lo tanto, el primer paso es definir la interfaz para su clase y subclase, independientemente de la implementación. Solo después de saber cuáles deberían ser las interfaces, debe diseñar la implementación de cada una.

Independientemente de si una propiedad es externamente mutable, la variable de instancia de respaldo puede necesitar ser mutable. La clase puede necesitar mutar su propiedad puramente internamente.

Puede hacer que la clase base tenga un inicializador designado que tome el objeto de matriz como un parámetro (del tipo id para que la anulación de la subclase no tenga que emitirse para tratarlo como NSMutableArray*). Entonces, los inicializadores "normales" de la clase llamarían a ese inicializador designado con el NSArray para usar. El inicializador designado de la subclase llamaría al inicializador designado de la superclase, pasando el NSMutableArray para usar.

Alternativamente, los inicializadores de la clase base podrían llamar a otro método para obtener la matriz. La implementación de la clase base devolvería un NSArray. La subclase podría anular ese método para devolver un NSMutableArray.