Редактирование одного объекта в NSMutableArray также изменяет другой объект в NSMutableArray - PullRequest
2 голосов
/ 08 октября 2010

У меня было навигационное приложение, которое работало нормально. В табличном представлении последний элемент называется «добавить элемент», и если пользователь нажал на него, он создал бы новый объект и передал бы его в другое представление, где пользователь мог бы ввести сведения для этого объекта. Когда пользователь вернется к предыдущему экрану, новый объект отобразится в массиве, который отображался в таблице.

Я изменил его так, чтобы поле «Добавить элемент» всегда было первым, а не последним. Я внес соответствующие изменения, чтобы массив правильно отображался на столе. Однако сейчас я замечаю странное поведение.

Если я отредактирую первый объект в массиве, 7-й объект также изменится на тот же, что и этот объект. Если я отредактирую второй объект в массиве, четвертый и шестой объекты также изменятся на одинаковые. Если я отредактирую третий элемент в массиве, пятый объект изменится на тот же.

Что может происходить?

В viewDidLoad: метод я инициализирую объект следующим образом:

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

Этот метод выполняется, когда пользователь выбирает строку в таблице

- (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];

}

Вот так выглядит viewWillAppear. Он обновит таблицу после редактирования объекта.

- (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];
        }

    }

}

Редактировать: Я решаю проблему, реализуя NSCopy для объекта person, а затем делаю копию объекта из массива, вместо того, чтобы напрямую указывать на объект в массиве. Кто-нибудь знает, почему это решило проблему?

Ответы [ 2 ]

3 голосов
/ 31 октября 2010

Редактировать: Я решаю проблему, внедряя NSCopy для объекта person, а затем делаю копию объекта из массива вместо прямого указания на объект в массиве.Кто-нибудь знает, почему это решило проблему?

Первоначально гарантированная проблема заключалась в том, чтобы иметь несколько одинаковых PersonDetails в массиве.Если бы вы сделали что-то вроде:

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

, я бы поспорил, что некоторые адреса будут одинаковыми, указывая на один и тот же объект в массиве несколько раз.

Именно поэтому копированиеОбъект "исправил" проблему.Вы скрываете изворотливую логику, которая привела к описанной выше ситуации, делая копию при каждой вставке.

1 голос
/ 08 октября 2010

эта часть выглядит немного странной в отношении владения памятью:

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;

т.е. @property(??) personDetails

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...