iosmemory-managementmemory-corruptionloadnibnamed

ios: Why is a temporary load of XIB, to get frame height, corrupting memory?


I am using trying to get the heights for several UITableCellView's that are defined in their own XIB. I create a list of the heights that are used in the callback heightForRowInPathIndex of the UITableViewDelegate. When I do this, the application crashes as-if a memory corruption.

arrayOfTableCellView = [[NSBundle mainBundle] loadNibNamed:@"TableCellXyz" owner:self options:nil];

UITableViewCell *cellOfXyz = (UITableViewCell*) [arrayOfTableCellView objectAtIndex:0];

[arrayCellHeights insertObject:[NSNumber numberWithInt:cellOfAlerts.frame.size.height] atIndex:kIndexXyz];

[arrayOfTableCellView release];

I have looked at the retainCount and it is as expected.


Solution

  • Well the answer is simple, from the docs:

    Return Value

    An array containing the top-level objects in the nib file. The array does not contain references to the File’s Owner or any proxy objects; it contains only those objects that were instantiated when the nib file was unarchived. You should retain either the returned array or the objects it contains manually to prevent the nib file objects from being released prematurely.

    It seems like you are just assigning the return value to arrayOfTableCellView. If you want to retain the return value, and arrayOfTableCellView is actually a property on your viewController, then you should assign it using self.arrayOfTableCellView.

    If you are not retaining it, you don't have to release it because you do not own it. So when you actually get the array like this

    NSArray *arrayOfTableCellView = [[NSBundle mainBundle] loadNibNamed:@"TableCellXyz" owner:self options:nil];
    

    then you don't want to have

    [arrayOfTableCellView release];
    

    in there, because you didn't allocate the object.

    EDIT:

    Just to calarify this to you, I just ran your code, with the expected result:

    NSArray * arrayOfTableCellView = [[NSBundle mainBundle] loadNibNamed:@"JLUViewController" owner:self options:nil];
    
    UITableViewCell *cellOfXyz = (UITableViewCell*) [arrayOfTableCellView objectAtIndex:0];
    
    [arrayCellHeights insertObject:[NSNumber numberWithInt:cellOfAlerts.frame.size.height] atIndex:kIndexXyz];
    

    The above code does not crash or cause a leak. Instruments does not report a leak, so you'd be fine.

    If you add

    [arrayOfTableCellView release];
    

    though it will crash, reporting EXC_BAD_ACCESS, because you tried to release an object you didn't own. Notice how i made the NSArray a local variable? You should do the same because you don't need it to be a property, since you just use it inside the function's scope. Also please not that if arrayCellHeights is a property inside your viewcontroller, always use self.arrayCellHeights to access it.