views:

64

answers:

2

I had a navigation application that was working normally. In the table view, the last item is called "add item", and if the user pressed it, it would create a new object and pass it to another view where the user could enter the details for that object. When the user returned to the previous screen, the new object would show in the array which was displayed in the table.

I changed it so that the "add item" field is always the first field in the table, not the last. I made the appropriate changes so that the array would display correctly on the table. However, now I am noticing strange behavior.

If I edit the first object in the array, the 7th object also changes to be the same as this object. If I edit the second object in the array, the fourth and sixth object also change to be the same. If I edit the third item in the array, the fifth object changes to be the same.

What could be happening?

In the viewDidLoad: method I initialize the object like this:

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

This is the method that gets executed when a user selects a row on the 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];

}

This is what the viewWillAppear looks like. It will update the table after an object has been edited.

- (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: I solve the problem by implementing NSCopy for the person object and then making a copy of the object from the array instead of directly pointing to the object in the array. Anyone know why this solved the problem?

+1  A: 

this part here looks a bit dodgy with regard to memory ownership:

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;

i.e. @property(??) personDetails

Anders K.
In the h file I have @property (nonatomic, retain) PersonDetails *personDetails and then I synthesize it in the m file.
awakeFromNib
ok so you get a leak then in the above code personDetails = [[PersonDetails alloc] init] (not that helps you with your issue)
Anders K.
To which instance are you referring? Are you talking about the one in didSelectRowAtIndexPath? That's there because a new object has to be created since the user will be adding a new object.
awakeFromNib
+2  A: 

Edit: I solve the problem by implementing NSCopy for the person object and then making a copy of the object from the array instead of directly pointing to the object in the array. Anyone know why this solved the problem?

The original problem was pretty much guaranteed to be an issue of having the same PersonDetails in the array multiple times. If you were to do something like:

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

I'd bet that some of the addresses would be the same, indicating same object in array multiple times.

Which is why copying the object "fixed" the problem. You are hiding the dodgy logic that led to the above situation by making a copy on every insertion.

bbum