views:

185

answers:

2

Disclaimer first: I'm pretty new to Objective-C and the retain model. I've been developing in a garbage collected .NET environment for the last five years, so I've been spoiled. I'm still learning.

I'm having my iPhone app crash with EXC_BAD_ACCESS. It happens in a navigtation controller/tableview setup. When I select a row the first time, no problems. It switches in the child controller without problems. I go back and select the same row again. Program then proceeds to crash. Every other row works fine, but every second time a row is accessed, it's a crash.

I've pinpointed the location where this happens. The child controller (which is a class that I reuse for every row of the same type) that's being switched into has an array of NSString's representing the rows that will be displayed. I set it before pushing the child viewcontroller. It's there where this apparently happens.

I'm having a hard time debugging this problem, still wrestling with xcode and all. I fear there may be some vital information missing here, but maybe there is something you recognize.

+2  A: 

Enable NSZombies.

http://www.cocoadev.com/index.pl?NSZombieEnabled

That will help you identify the object that is being over-released (probably what is going on).

xyzzycoder
My app still crashed and went back to springboard in the simulator. Isn't that what's *not* supposed to happen with this enabled? I did get a nice line in the debugger console, though, telling me which method was sent to the deallocated instance (isEqualToString)
Thaurin
Make sure that you run debug, and set a breakpoint on "raise."In the console (you'll want the raise function when prompted):b raise
xyzzycoder
A: 

So... [UINavigationController pushViewController] does not retain, does it? ;) What I did was init/alloc the controller that was going to be pushed on the navigation stack, push it and then release it. I thought the navigation controller would retain the controller. Apparently, it did not. It obviously worked the first time it was pushed, but not the second. I guess that's where the memory really got freed. Enabling zombies revealed that it was getting messages (from setters) to a deallocated object.

Why did I think pushViewController would retain the controller? I don't know; I think I got confused thinking that if you alloc it, you are also responsible for deallocing it. I somehow thought that after pushing it, it would be the navigation controller's responsibility. Seems I was wrong.

I'm still learning to get a feel for this (evil C# and garbage collection has fried my mind!). Anyone have anything to add?

To illustrate, this seems to have been wrong:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
     NSUInteger section = [indexPath section];
 NSUInteger row = [indexPath row];

 if (selectionController == nil)
 {
  selectionController =
   [[ConfigSelectionViewController alloc] initWithStyle:UITableViewStyleGrouped];
 }

 NSString *title = [self titleForSection:section row:row];
 NSString *key = [self keyForSection:section row:row];

 selectionController.configKey = key;
 selectionController.title = title;

 NSArray *listItems = [self itemsForSection:section row:row];
 selectionController.list = listItems;

 [self.navigationController pushViewController:selectionController animated:YES];

        // DON'T DO THIS!
        [selectionController release];


}
Thaurin
This is incorrect. UINavigationController does retain when pushing a new view controller. There is a bug somewhere else in your code!
Rengers
You are absolutely right. I found it out this morning. I was actually releasing an object in an array through a pointer to it, while that wasn't at all the intention! I stupidly thought the pointer was retaining it.So problem solved. Thanks for the comfirmation, though.
Thaurin