objective c - NSArray @property respaldado por un NSMutableArray
objective-c ios (6)
Básicamente, ponga la propiedad NSArray en una categoría en su archivo de encabezado y la propiedad NSMutableArray en la extensión de clase en su archivo de implementación. Al igual que...
Foo.h:
@interface Foo
@end
@interface Foo (Collections)
@property (nonatomic, readonly, strong) NSArray *someArray;
@end
Foo.m
@interface Foo ()
@property (nonatomic, readwrite, strong) NSMutableArray *someArray;
@end
Definí una clase en la que me gustaría que apareciera una propiedad pública como si NSArray
respaldada por un NSArray
. Eso es bastante simple, pero en mi caso el respaldo real es un NSMutableArray
:
@interface Foo
{
NSMutableArray* array;
}
@property (nonatomic, retain) NSArray* array;
@end
En mi archivo de implementación ( *.m
), yo @synthesize
la propiedad, pero inmediatamente encuentro advertencias porque usar self.words
es lo mismo que tratar de modificar un NSArray
.
¿Cuál es la forma correcta de hacer esto?
¡Gracias!
Declararía un NSArray
readonly
en su encabezado y anularía el getter para que esa matriz devuelva una copia de un NSMutableArray
privado declarado en su implementación. Considera lo siguiente.
Foo.h
@interface Foo
@property (nonatomic, retain, readonly) NSArray *array;
@end
Foo.m
@interface Foo ()
@property (nonatomic, retain) NSMutableArray *mutableArray
@end
#pragma mark -
@implementation Foo
@synthesize mutableArray;
- (NSArray *)array
{
return [[self.mutableArray copy] autorelease];
}
@end
Eso es porque su propiedad debe coincidir con el tipo de clase de ivar real.
Una posible solución / solución:
//Foo.h:
@interface Foo
{
NSMutableArray* mutableArray;
}
@property (readwrite, nonatomic, retain) NSArray* array;
//or manual accessor declarations, in case you''re picky about wrapper-properties.
@end
//Foo.m:
@interface Foo ()
@property (readwrite, nonatomic, retain) NSMutableArray* mutableArray;
@end
@implementation
@synthesize mutableArray;
@dynamic array;
- (NSArray *)array {
return [NSArray arrayWithArray:self.mutableArray];
}
- (void)setArray:(NSArray *)array {
self.mutableArray = [NSMutableArray arrayWithArray:array];
}
@end
Está agregando una propiedad mutableArray
privada en una extensión de clase y haciendo que la array
pública simplemente se reenvíe a su mutable privada.
Con las extensiones de lenguaje más recientes de ObjC, tiendo a eliminar el
{
NSMutableArray* mutableArray;
}
ivar bloquear por completo, si es posible.
Y defina el ivar a través de la sintetización, como tal:
@synthesize mutableArray = _mutableArray;
que generará un NSMutableArray *_mutableArray;
instancia para ti.
Respuesta más simple: su tipo de propiedad (NSArray) no coincide con su tipo de variable de instancia (NSMutableArray).
Esta es otra buena razón por la que no debe definir sus propias variables de respaldo. Deje @synthesize configurar sus variables de instancia; no lo hagas a mano.
Sencillo:
1) No use una propiedad cuando no sea una.
2) El código se simplifica a:
- (NSArray *)currentArray {
return [NSArray arraywithArray:mutableArray]; // need the arrayWithArray - otherwise the caller could be in for surprise when the supposedly unchanging array changes while he is using it.
}
- (void)setArray:(NSArray *)array {
[mutableArray setArray:array];
}
Cuando se asigna el objeto, crea la matriz y, cuando muera, desasula la matriz.
Cuando ocurren grandes efectos con el simple uso de un ''.'' operador, es fácil pasar por alto un código enormemente ineficiente. Los accesorios son solo eso. Además, si alguien llama a Foo.array, el contrato es para obtener acceso a los miembros de la matriz de foo, pero en realidad es solo una copia en el momento de la llamada. La diferencia es lo suficientemente real como para causar errores en las otras implementaciones publicadas aquí.
Actualización: esta respuesta ya no es válida. Use una de las soluciones sugeridas a continuación.
Estos días puedes hacer lo siguiente:
Foo.m:
@implementation Foo {
NSMutableArray* _array;
}
@end
Foo.h:
@interface Foo
@property (readonly, strong) NSArray* array;
@end
Todavía puede abordar _array mutable por ivar desde el interior de la implementación y fuera de él será accesible a través de la propiedad inmutable. Desafortunadamente, esto no garantiza que otros no puedan convertirlo a NSMutableArray y modificarlo. Para una mejor protección contra los idiotas, debe definir el método de acceso y devolver la copia inmutable, sin embargo, eso podría ser muy costoso en algunos casos.
De hecho, estoy de acuerdo con uno de los comentarios anteriores que es mejor usar métodos de acceso simples si necesita devolver algunos datos de solo lectura, definitivamente es menos ambiguo.