2009-08-03 6 views
7

Sono piuttosto nuovo all'obiettivo-c e provo a creare una piccola app per l'iphone.
Ho quasi finito con questo piccolo errore qui. In realtà, ho cercato ore con google per trovare una soluzione adeguata, ma sfortunatamente non sono in grado di trovare una soluzione che funzioni.
Sto usando questo tutorial qui per costruire un UITableView: UITableView Tutorial Il messaggio di errore completo è simile al seguente:obiettivo-c "metodo di mutazione inviato all'oggetto immutabile" errore

* Chiusura di applicazione a causa di eccezione non identificata 'NSInternalInconsistencyException', la ragione: '* - [ NSCFArray InsertObject: atIndex:]: metodo di mutazione inviato oggetto immutabile'

Questo è il controller dati di intestazione: 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 

..... 

e il metodo Titolare del trattamento: 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; 

} 

----------------------------- - in avanti nel codice sorgente ---------------------------------

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

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

} 

Vorrei apprezzo molto qualsiasi aiuto.

Grazie per il vostro supporto in anticipo.

Daniel

risposta

27

invio del copia messaggio a un NSMutableArray - come nella seguente dichiarazione in init - restituisce una copia immutabile.

self.tableList = [localList copy]; 

documentazione Cocoa usa la parola immutabile per riferirsi a sola lettura, non posso, essere-cambiato-dopo-inizializzazione oggetti. Di conseguenza, la chiamata successiva a addObject: non riesce con un messaggio di errore.

Nota come l'istruzione di assegnazione sopra non attiva alcun avviso del compilatore. copia restituisce un id, che si adatta confortevolmente - per quanto riguarda il compilatore - nel TableList di NSMutableArray *. Non c'è neanche un errore di runtime qui, dato che nessun messaggio viene passato in giro; un puntatore NSArray viene appena inserito in una variabile del puntatore NSMutableArray.

Per ottenere una copia mutabile, utilizzare invece mutableCopy.

notare che sia copia e mutableCopy creare un nuovo array e copiare il contenuto della originale ad esso. Una modifica della copia non si rifletterà nell'originale. Se hai solo bisogno di un altro riferimento alla matrice originale, utilizzare mantenendo invece.

È possibile trovare ulteriori dettagli nella sezione di discussione dello copyWithZone reference e nello NSMutableCopying protocol reference.

5

Si sta eseguendo, in pratica, le regole di gestione della memoria di Cocoa (specifically, these details). Se è presente un oggetto con immutable version e una versione mutabile, l'invio di -copy a un oggetto restituirà un oggetto immutabile.

Passiamo attraverso la parte pertinente.

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

Questo crea un nuovo array vuoto modificabile di tua proprietà. Belle.

self.tableList = [localList copy]; 

Questo crea un immutabile copia dell'array vuoto . Inoltre, sei il proprietario di questa copia appena creata. Sono due oggetti che possiedi in questo momento.

Assegna inoltre l'oggetto copiato alla proprietà tableList. Diamo un'occhiata alla dichiarazione di proprietà:

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

Questa proprietà viene dichiarata con l'copy attribute, così ogni volta che un nuovo valore viene assegnato ad esso, un altro metodo -copy viene inviato ad esso. Questa terza copia, tuttavia, non è di tua proprietà: è di proprietà dell'oggetto.

[localList release]; 

Che rilascia la matrice mutabile originale vuota. Bene, ma c'è ancora quello che hai fatto nella seconda linea fluttuante, inedito. Questa è una perdita di memoria.

Se è effettivamente necessaria una copia mutabile di qualcosa, si desidera il metodo -mutableCopy. (La documentazione per questi metodi si trova in NSCopying e NSMutableCopying.) Tuttavia, non si otterrà mai una versione mutabile di qualcosa in una proprietà con l'attributo copy, poiché invierà -copy a qualunque sia assegnato. La tua struttura dovrebbe utilizzare l'attributo retain anziché l'attributo copy, e il codice per inizializzare dovrebbe apparire qualcosa di simile:

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

Oppure, una versione più breve:

self.tableList = [NSMutableArray array]; 

Non c'è bisogno di copiare qualsiasi cosa in questa situazione, stai solo creando un nuovo oggetto.

+1

Se una proprietà copia è davvero chiamato per, poi la sostituzione di un conservano proprietà sta per essere una soluzione povera. Poiché non esiste una parola chiave mutablecopy, dichiarare la proprietà come copia, ma scrivere il proprio accessor invece di utilizzare accessors sintetizzati. –

+0

Buon punto. Vorrei anche dire che non vedo quasi mai oggetti che pubblicizzano la proprietà 'NSMutableArray'. Il purista in me vorrebbe vedere un setter personalizzato che memorizza una copia mutabile dell'oggetto e un getter personalizzato che restituisce una copia immutabile autorizzata. –

0

Ciao invece di mutableCopy credo che "strong" possa essere utilizzato anche per affrontare questo problema. Ho avuto anche problemi simili nel mio codice a causa dell'uso di "copy" anziché "strong". Così la linea di seguito:

@property (copy, nonatomic) NSMutableArray *computers; 

Dovrebbe essere:

@property (strong, nonatomic) NSMutableArray *computers; 

auguriamo che possa essere di grande aiuto per i principianti fare errori come me.

1

Se si sta assegnando la LocalList da un altro oggetto potrebbe essere che non è Mutabile in quel caso può attraverso questo tipo di errore.

Spero possa essere utile.

self.tableList = [localList mutableCopy]; 
0

Questo risolverà il problema:

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