iphone - NSMutableArray addObject:-[__ NSArrayI addObject:]: selector no reconocido enviado a la instancia
(8)
Intenté inicializar mi NSMutableArray 100 formas a partir del domingo, y NADA funciona para mí. Intenté configurarlo igual a un NSMutableArray recién asignado e inicializado, solo asignando, inicializando la variable por sí mismo, cada combinación que podía pensar y siempre el mismo resultado.
Aquí está el código:
Object.h
NSMutableArray *array;
@property (copy) NSMutableArray *array;
Object.m
@synthesize array;
if ( self.array ) {
[self.array addObject:anObject];
}
else {
self.array = [NSMutableArray arrayWithObjects:anObject, nil];
}
NOTA: En depuración, "anObject" NO es nulo en el momento de la ejecución ...
He probado un Objeto y lo es. La inicialización funciona muy bien, pero sigo recibiendo el siguiente error cuando trato de agregarObjeto: a self.array.
2010-07-10 11: 52: 55.499 MyApp [4347: 1807] - [__ NSArrayI addObject:]: selector no reconocido enviado a la instancia 0x184480
2010-07-10 11: 52: 55.508 MyApp [4347: 1807] *** Aplicación de finalización debido a una excepción no detectada ''NSInvalidArgumentException'', razón: ''- [__ NSArrayI addObject:]: selector no reconocido enviado a la instancia 0x184480''
¿Alguien tiene alguna idea de lo que está pasando?
Como estaba probando la lectura de mi publicación, se me ocurrió una idea y respondí mi propia pregunta. Esta resolución fue tan poco clara que decidí seguir adelante, crear la publicación y responderla yo mismo (para que ningún otro novato, como yo, no se quede colgado).
Mi error fue en ...
@property (copy) NSMutableArray *array;
debería haber sido...
@property (retain) NSMutableArray *array;
El error no estaba sucediendo en la forma en que estaba ejecutando mi código, sino más bien en la forma en que el objeto anObject estaba tratando de "copiar" la matriz NSMutableArray.
Como todos sabemos...
mutableArray = [mutableArray copy];
no es siempre (o nunca, en mi experiencia) igual a ...
mutableArray = [mutableArray mutableCopy];
Y esta fue la fuente de mi problema. Simplemente al cambiar @property de (copiar) a (retener) resolví mi problema.
El error se produjo como resultado de intentar agregar un objeto a un tipo NSMutableArray que apuntaba a un objeto NSArray. Este tipo de escenario se muestra en algunos códigos de demostración a continuación:
NSString *test = @"test";
NSMutableArray *mutableArray = [[NSMutableArray alloc] init];
[mutableArray addObject:test];
NSArray *immutableArray = [[NSArray alloc] init];
mutableArray = immutableArray;
[mutableArray addObject:test]; // Exception: unrecognized selector
Del código anterior, es fácil ver que un tipo de subclase se está asignando a un tipo de superclase. En Java, por ejemplo, esto se habría marcado inmediatamente como un error (error de conversión entre tipos) y el problema se resolvió con bastante rapidez. Para ser justos con Objective-C, se da una advertencia cuando se intenta realizar una tarea incompatible, sin embargo, esto simplemente no parece ser suficiente a veces y el resultado puede ser un verdadero dolor para los desarrolladores. Afortunadamente, esta vez, no fui yo quien soportó la mayor parte de este dolor: P
El setter sintetizado para @property (copy)
envía un mensaje de copy
a la matriz, lo que da como resultado una copia inmutable.
No tiene más remedio que implementarlo usted mismo aquí, como se detailed en la guía Objective-C.
Esta excepción puede suceder si uno de los objetos en la matriz es nulo.
Fui mordido por esta excepción por un error tipográfico que hice, tal vez le ahorrará a alguien 5 min. de su tiempo:
Escribí:
NSMutableArray *names = [NSArray array];
en lugar de:
NSMutableArray *names = [NSMutableArray array];
El compilador no tiene ningún problema con eso porque NSMutableArray también es un NSArray, pero se bloquea al intentar agregar un objeto.
Me gustaría inclinar mi sombrero a Georg Fritzsche. Terminé necesitando usar (copiar) en lugar de (retener), y no habría sabido qué hacer sin su aporte.
//@property (copy) NSMutableArray *array;
@property (nonatomic, copy) NSMutableArray *array; //overridden method is non-atomic as it is coded and should be reflected here.
Si desea utilizar (copiar) en un objeto mutable, debe anular el método "setter" de la siguiente manera ...
- (void)setArray:(NSArray *)newArray {
if ( array != newArray ) {
[array release];
array = [newArray mutableCopy];
// [array retain]; // unnecessary as noted by Georg Fritzsche
}
return;
}
NOTA: Obtendrá una advertencia del compilador: Incompatible Objective-C tipos inicializando ''struct NSArray *'', esperado ''struct NSMutableArray *'' Decidí declarar el nuevo parámetro Array como un (NSArray *), porque se le da la flexibilidad de tener cualquier array pasado y copiado correctamente a su variable (NSMutableArray *). Si desea declarar el nuevo parámetro Array como (NSMutableArray *), deberá dejar el método mutableCopy en su lugar para obtener los resultados deseados.
¡Saludos a Georg! Z @ K!
Obtuve el mismo error, aunque mis propiedades eran fuertes (usando ARC) y asigné la matriz con NSMutableArray.
Lo que sucedía era que estaba archivando la matriz mutable (ya que contiene objetos personalizados) para su uso futuro y, al decodificarla, devuelve una copia inmutable.
Espero que ayude a cualquiera por ahí.
Tiene algunos índices (en una matriz de datos en otro lugar) y desea tenerlos en orden numérico (por una buena razón). Se bloquea hasta que se agrega mutableCopy al final. Totalmente desconcertado, hasta que recordé que el uso de Objective-C literal @ [] devuelve una matriz no mutable .
NSMutableArray *a = [@[@(self.indexA), @(self.indexB)] mutableCopy];
NSLog(@"%@", a);
[indexArray sortUsingComparator: ^(NSNumber *obj1, NSNumber *obj2) {
return [obj1 compare:obj2];
}];
NSLog(@"%@", a);
Gracias, Zak!