Search code examples
iphonedealloc

iPhone EXC_BAD_ACCESS when calling [super dealloc] on a custom UIViewController


I'm at a loss! It's one of those pesky bugs that happens only under specific conditions, yet I cannot link the conditions and the results directly.

My app has a paged UIScrollView where each page's view comes from a MyViewController, a subclass of UITableViewController. To minimize memory usage I unload those controllers that are not currently visible. Here is my "cleaning" method:

- (void) cleanViewControllers:(BOOL)all {

    if (all) { 
    // called if some major changes occurred and ALL controllers need to be cleared

        for (NSInteger i = 0; i < [viewControllers count]; i++)
            [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
    }
    else if ([viewControllers count] > 2) {
    // called if only the nearest, no longer visible controller need to be cleared
        NSInteger i = pageControl.currentPage - 2;
        if (i > -1) [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
        i = pageControl.currentPage + 2;
        if (i < [viewControllers count]) [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
    }
}

It's this line that crashes the app:

viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];

viewControllers is an NSMutableArray containing objects of type MyViewController. MyViewController has no custom properties and its dealloc method contains nothing but a [super dealloc] call.

Here is what the debugger shows: alt text http://a.imageshack.us/img831/3610/screenshot20100806at126.png

The thing is that this does not happen every time the controller is cleared, but only sometimes. Specifically, after certain changes trigger a complete cleaning and re-drawing of the ScrollView, it displays the current page (call it X) fine, but as soon as I scroll far enough to cause cleaning of X, this crash happens. It's driving me nuts!

Another thing, this does not happen in the 4.0 Simulator, nor on an iPad, but happens very consistently on a 1st gen iPod touch running 3.1.3.


Solution

  • Something is being released but a pointer is still dangling. Set NSZombieEnabled to YES and run it again. Here's how:

    • Product -> Edit Scheme
    • Select the "Arguments" tab
    • Add to "Variables to be set in the environment"
      • Name: NSZombieEnabled
      • Value: YES

    In Xcode 4.1 and above:

    • Product -> Edit Scheme
    • Select the "Diagnostics" tab
      • You have an option to enable zombie objects.

    Run the app again. At some point it'll tell you you're accessing an already released object. From that you'll need to figure out who's not retaining or who's over-releasing the object.

    Happy Zombie Hunting.