2009-08-03 15 views
7

Je suis assez nouveau à l'objectif-c et essayer de créer une petite application pour l'iphone.
J'ai presque terminé cette petite erreur ici. En fait, j'ai cherché des heures avec google pour trouver une bonne solution, mais malheureusement, je ne suis pas en mesure de trouver une solution qui fonctionne.
J'utilise ce tutoriel ici pour construire une UITableView: UITableView Tutorial Le message d'erreur complet ressemble à ceci:objectif-c "méthode de mutation envoyée à l'objet immuable" erreur

* Mettre fin application en raison d'une exception non interceptée 'NSInternalInconsistencyException', raison: « * - [ NSCFArray insertObject: atIndex:]: méthode envoyé à muter objet immuable »

C'est le contrôleur de données en-tête: 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 

..... 

et le contrôleur de données Méthode: 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; 

} 

----------------------------- --plus tard dans le code source ---------------------------------

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

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

} 

Je voudrais Appréciez à peu près toute aide.

Nous vous remercions de votre soutien à l'avance.

Daniel

Répondre

27

Envoi de la copie message à un NSMutableArray - comme dans la déclaration suivante dans initialisation - retourne une copie immuable.

self.tableList = [localList copy]; 

documentation Cocoa utilise le mot immuable de se référer à la lecture seule, ne-être-changed-après l'initialisation des objets. Par conséquent, l'appel subséquenct à addObject: échoue avec un message d'erreur.

Notez que l'instruction d'assignation ci-dessus ne déclenche aucun avertissement du compilateur. copy renvoie un id, qui s'adapte confortablement - en ce qui concerne le compilateur - dans le NSMutableArray * tableList. Il n'y a pas non plus d'erreur d'exécution ici, car aucun message n'est transmis; un pointeur NSArray est simplement placé dans une variable de pointeur NSMutableArray.

Pour obtenir une copie mutable, utilisez mutableCopy à la place.

Notez que les deux copie et mutableCopy créer un nouveau tableau et copier le contenu de l'original à elle. Une modification de la copie ne sera pas reflétée dans l'original. Si vous avez juste besoin d'une autre référence au tableau original, utilisez à la place, retenez.

Vous pouvez trouver plus de détails dans la section discussion du copyWithZone reference et dans le NSMutableCopying protocol reference.

5

Vous rencontrez, fondamentalement, les règles de gestion de la mémoire de Cocoa (specifically, these details). S'il y a un objet avec un immutable version et une version mutable, l'envoi de -copy à un objet renverra un objet immuable.

Parcourons la partie pertinente. Cela crée un nouveau tableau vide mutable que vous possédez. Bien.

self.tableList = [localList copy]; 

Cela crée une copie immuable du tableau vide. De plus, vous possédez cette copie fraîchement créée. C'est deux objets que vous possédez en ce moment.

Ceci affecte également votre objet copié à la propriété tableList. Regardons la déclaration de propriété:

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

Cette propriété est déclarée avec le copy attribute, donc chaque fois qu'une nouvelle valeur est affectée à elle, une autre méthode -copy est envoyée. Cependant, cette troisième copie ne vous appartient pas, elle appartient à l'objet.

[localList release]; 

Cela libère le tableau mutable vide d'origine. Très bien, mais il y a toujours celui que vous avez fait en deuxième ligne qui flotte, inédit. C'est une fuite de mémoire.

Si vous avez réellement besoin d'une copie modifiable de quelque chose, vous voulez la méthode -mutableCopy. (La documentation de ces méthodes se trouve sous NSCopying et NSMutableCopying.) Cependant, vous n'allez jamais obtenir une version modifiable de quelque chose dans une propriété avec l'attribut copy, car il enverra -copy à tout ce qui lui est assigné. Votre propriété doit utiliser l'attribut retain au lieu de l'attribut copy, et le code pour l'initialiser devrait ressembler à ceci:

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

Ou, une version plus courte:

self.tableList = [NSMutableArray array]; 

Il n'y a pas besoin de copier quoi que ce soit dans cette situation, vous créez juste un objet frais.

+1

Si une propriété de copie est vraiment appelé, puis substituer une propriété va conserver être une mauvaise solution. Comme il n'y a pas de mot clé mutablecopy, déclarez la propriété en tant que copie, mais écrivez votre propre accesseur au lieu d'utiliser des accesseurs synthétisés. –

+0

Bon point. J'ajouterais que je ne vois presque jamais d'objets qui annoncent une propriété 'NSMutableArray'. Le puriste en moi voudrait voir un setter personnalisé qui stocke une copie mutable de l'objet et un getter personnalisé qui renvoie une copie immuable libeleased. –

0

Salut au lieu de mutableCopy Je crois que "strong" peut également être utilisé pour résoudre ce problème. J'ai eu le même problème dans mon code à cause de l'utilisation de "copy" au lieu de "strong". Ainsi, la ligne ci-dessous:

@property (copy, nonatomic) NSMutableArray *computers; 

Il devrait être:

@property (strong, nonatomic) NSMutableArray *computers; 

espère que ce sera d'un grand secours pour les débutants de faire des erreurs comme moi.

1

Si vous attribuez localList d'un autre objet peut être ce n'est pas Mutable dans ce cas, il peut par ce type d'erreur.

J'espère que ce sera utile.

self.tableList = [localList mutableCopy]; 
0

Cela permettra de résoudre le problème:

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