2010-10-08 11 views
2

J'avais une application de navigation qui fonctionnait normalement. Dans la vue de table, le dernier élément est appelé "ajouter un élément", et si l'utilisateur le pressait, il créerait un nouvel objet et le passerait à une autre vue où l'utilisateur pourrait entrer les détails pour cet objet. Lorsque l'utilisateur revenait à l'écran précédent, le nouvel objet s'affichait dans le tableau qui était affiché dans la table.Modifier un objet dans un NSMutableArray modifie également un autre objet dans le NSMutableArray

Je l'ai modifié pour que le champ "ajouter un élément" soit toujours le premier champ de la table, pas le dernier. J'ai fait les changements appropriés pour que le tableau s'affiche correctement sur la table. Cependant, maintenant je remarque un comportement étrange.

Si j'édite le premier objet du tableau, le septième objet change également pour être identique à cet objet. Si je modifie le deuxième objet dans le tableau, les quatrième et sixième objets changent également pour être identiques. Si je modifie le troisième élément dans le tableau, le cinquième objet change pour être le même.

Que pourrait-il se passer?

Dans la viewDidLoad: méthode que j'initialiser l'objet comme ceci:

PersonDetails *personDetails = [[PersonDetails alloc] init]; 

Ceci est la méthode qui est exécuté lorsqu'un utilisateur sélectionne une ligne sur la table

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
// Navigation logic may go here. Create and push another view controller. 
updatePersonArray = YES; 
arrayIndex = indexPath.row-1;  
editPerson = [[EditClassController alloc] initWithNibName:@"EditPerson" bundle:nil];  
editPerson.title = @"Edit Person"; 

if (arrayIndex != -1) { 
    personDetails = [classArray objectAtIndex:arrayIndex];  
} 
else { 
    personDetails = [[PersonDetails alloc] init]; 
} 
editPerson.personDetails = personDetails; 

[self.navigationController pushViewController:editPerson animated:YES]; 
[editPerson release]; 

}

Voici à quoi ressemble viewWillAppear. Il mettra à jour la table après qu'un objet a été modifié.

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 

    if ([personDetails isEmpty]) { 
     updatePersonArray = NO; 
    } 

    if (updatePersonArray) { 
     if (arrayIndex == -1) { 
      NSLog(@"adding new object to array"); 
      [personArray addObject:personDetails]; 
     } 
     else { 
      NSLog(@"replacing object at index %d", arrayIndex); 
      [personArray replaceObjectAtIndex:arrayIndex withObject:personDetails]; 
      } 

     [self saveArrayToDisk]; 

     [self.tableView reloadData]; 

     updatePersonArray = NO; 
    } 
    else { 
     //load the array from disk 
    NSLog(@"loading array from disk"); 
     NSData *theData = [[NSUserDefaults standardUserDefaults] objectForKey:@"personArray"]; 
     if (theData != nil) { 
      NSLog(@"found something"); 
      personArray = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:theData]]; 
     } 
     else { 
      personArray = [[NSMutableArray alloc] init]; 
     } 

    } 

} 

Edit: je résoudre le problème en mettant en œuvre NSCopy pour l'objet personne, puis faire une copie de l'objet à partir du tableau au lieu de pointer directement à l'objet dans le tableau. Quelqu'un sait pourquoi cela a résolu le problème?

+0

peut-être pourriez-vous montrer du code? semble que vous ne créez pas les objets et référencez plutôt le même objet dans le tableau. –

+0

J'ai créé des copies d'objets dans le tableau et cela a résolu le problème. –

Répondre

3

Edit: Je résous le problème en la mise en œuvre NSCopy pour l'objet personne puis faire une copie de l'objet du tableau au lieu de pointant directement vers l'objet dans le tableau . Quelqu'un sait pourquoi cela a résolu le problème ?

Le problème d'origine était à peu près garanti d'avoir plusieurs fois le même PersonDetails dans le tableau. Si vous deviez faire quelque chose comme:

for (id p in myArray) NSLog("%p", p); 

Je serais prêt à parier que certaines des adresses seraient les mêmes, ce qui indique un même objet dans un tableau à plusieurs reprises.

C'est pourquoi la copie de l'objet "corrigé" le problème. Vous cachez la logique douteuse qui a conduit à la situation ci-dessus en faisant une copie sur chaque insertion.

1

cette partie semble ici un peu louches en ce qui concerne la propriété de la mémoire:

if (arrayIndex != -1) { 
    // here you get back an autorelease object - which you haven't retained 
    personDetails = [classArray objectAtIndex:arrayIndex]; 
} 
else { 
    // here you create an object with retainCount =1 
    personDetails = [[PersonDetails alloc] init]; 
} 

// depending on your property attribute this may or may not work as you expect 
editPerson.personDetails = personDetails; 

-à-dire @property(??) personDetails

+0

Dans le fichier h j'ai @property (nonatomic, retain) PersonDetails * personDetails et ensuite je le synthétise dans le fichier m. –

+0

ok donc vous obtenez une fuite puis dans le code ci-dessus personDetails = [[PersonDetails alloc] init] (pas ce qui vous aide avec votre problème) –

+0

À quel exemple faites-vous référence? Parlez-vous de celui de didSelectRowAtIndexPath? C'est là parce qu'un nouvel objet doit être créé puisque l'utilisateur ajoutera un nouvel objet. –