2009-08-03 13 views
7

Soy bastante nuevo en Objective-C y trato de crear una pequeña aplicación para el iphone.
Casi he terminado al lado de este pequeño error aquí. De hecho, he buscado horas en Google para encontrar una solución adecuada, pero desafortunadamente no puedo encontrar una solución que funcione.
estoy usando este tutorial aquí para construir una UITableView: UITableView Tutorial El mensaje de error completo es el siguiente:objetivo-c "Método de mutación enviado al objeto inmutable" error

* Terminación de aplicación debido a excepción no detectada 'NSInternalInconsistencyException', razón: '* - [ NSCFArray InsertObject: atIndex:]: método mutando enviado al objeto inmutable'

Este es el encabezado del tratamiento de datos: MyLinksDataController.h

@interface MyLinksDataController : NSObject { 

NSMutableArray *tableList; //<---important part 

} 

- (unsigned)countOfList; 
- (id)objectInListAtIndex:(unsigned)theIndex; 
- (void)addData:(NSString *)data; //<---important part 
- (void)removeDataAtIndex:(unsigned)theIndex; 

@property (nonatomic, copy, readwrite) NSMutableArray *tableList; //<---important part 

..... 

y el método del tratamiento de datos: MyLinksDataController.m

#import "MyLinksDataController.h" 

@implementation MyLinksDataController 

@synthesize tableList; 

- (id)init { 

    if (self = [super init]) { 

     NSLog(@"Initilizing DataController"); 
     //Instantiate list 
     NSMutableArray *localList = [[NSMutableArray alloc] init]; 
     self.tableList = [localList copy]; 
     [localList release]; 

     //Add initial Data 
     [self addData:@"AAAAAAAAAAAAAA"]; 
     [self addData:@"BBBBBBBBBBBBBB"]; 

    } 

    return self; 

} 

----------------------------- --más adelante en el código fuente ---------------------------------

- (void)addData:(NSString*)data; { 

    [tableList addObject:data]; //<---- here the app crashes 

} 

apreciamos mucho cualquier ayuda.

Gracias por su ayuda con anticipación.

Daniel

Respuesta

27

El envío de la copia mensaje a un NSMutableArray - como en la siguiente declaración en init - Devuelve una copia inmutable.

self.tableList = [localList copy]; 

documentación de cacao se utiliza la palabra inmutable para referirse a sólo lectura,-cambiar-no puede-post-inicialización de objetos. Por lo tanto, la llamada subsiguiente al addObject: falla con un mensaje de error.

Observe cómo la instrucción de asignación anterior no desencadena ninguna advertencia del compilador. copia devuelve id, que se adapta cómodamente, en lo que respecta al compilador, en NSMutableArray * tableList. Aquí tampoco hay ningún error de tiempo de ejecución, ya que no se transmiten mensajes; un puntero NSArray se acaba de colocar en una variable de puntero NSMutableArray.

Para obtener una copia mutable, use mutableCopy en su lugar.

Tenga en cuenta que tanto copia y mutableCopy crear una nueva matriz y copiar el contenido del original a la misma. Un cambio en la copia no se reflejará en el original. Si solo necesita otra referencia a la matriz original, use y conserve en su lugar.

Puede encontrar más detalles en la sección de discusión de copyWithZone reference y en el NSMutableCopying protocol reference.

5

Te encuentras, básicamente, con las reglas de gestión de memoria de Cocoa (specifically, these details). Si hay un objeto con un immutable version y una versión mutable, el envío de -copy a un objeto devolverá un objeto inmutable.

Pasemos a través de la parte correspondiente.

NSMutableArray *localList = [[NSMutableArray alloc] init]; 

Esto crea una nueva matriz mutable vacía que usted posee. Multa.

self.tableList = [localList copy]; 

Esto crea un inmutable copia de la matriz vacía. Además, posee esta copia recién creada. Esos son dos objetos que posee en este momento.

Esto también asigna su objeto copiado a la propiedad tableList. Veamos la declaración de propiedad:

@property (nonatomic, copy, readwrite) NSMutableArray *tableList; 

Esta propiedad se declara mediante el copy attribute, por lo que cada vez que se asigna un nuevo valor a la misma, otro método -copy se envía a la misma. Sin embargo, esta tercera copia no es suya, es propiedad del objeto.

[localList release]; 

que libera la matriz mutable vacía original. Bien, pero aún está el que hiciste en la segunda línea flotando, inédito. Esa es una pérdida de memoria.

Si realmente necesita una copia mutable de algo, desea el método -mutableCopy. (La documentación para estos métodos se encuentra en NSCopying y NSMutableCopying). Sin embargo, nunca se obtendrá una versión mutable de algo en una propiedad con el atributo copy, ya que enviará -copy a lo que se le haya asignado. Su propiedad debe utilizar el atributo en lugar del atributo copyretain, y el código para inicializar debería ser algo como esto:

NSMutableArray *localList = [[NSMutableArray alloc] init]; 
self.tableList = localList; 
[localList release]; 

O, una versión más corta:

self.tableList = [NSMutableArray array]; 

No hay necesidad de copiar cualquier cosa en esta situación, solo estás creando un objeto nuevo.

+1

Si una propiedad copia es realmente necesario, a continuación, sustituyendo un retienen la propiedad va a ser una mala solución. Como no hay una palabra clave mutablecopy, declare la propiedad como copia, pero escriba su propio acceso en lugar de usar accesores sintetizados. –

+0

Buen punto. También agregaría que casi nunca veo objetos que publiciten una propiedad 'NSMutableArray'. El purista en mí desearía ver un setter personalizado que almacene una copia mutable del objeto y un getter personalizado que devuelva una copia inmutable que se haya lanzado automáticamente. –

0

Hola en lugar de mutableCopy, creo que "strong" también se puede utilizar para hacer frente a este problema. También tuve un problema similar en mi código debido al uso de "copy" en lugar de "strong". Por lo que la línea de abajo:

@property (copy, nonatomic) NSMutableArray *computers; 

Debería ser:

@property (strong, nonatomic) NSMutableArray *computers; 

Esperamos que sea de gran ayuda para los principiantes cometer errores como yo.

1

Si está asignando localList desde otro objeto puede ser que no sea Mutable, en ese caso puede hacerlo a través de este tipo de error.

Espero que sea útil.

self.tableList = [localList mutableCopy]; 
0

Esto resolverá el problema:

NSMutableArray *localList = [[NSMutableArray alloc] init]; 
self.localList = [[NSMutableArray alloc]initWithArray:localList]; 
Cuestiones relacionadas