Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EXC_BAD_ACCESS with IBACTION

I have read a lot about this issue but mine still seems to be different somehow. So from what I understood, EXC_BAD_ACCESS occurs with memory management problems.

The thing is, mine does not seem (! :)) to be there. The thing is, I simple added a button in IB, rounded rect, no image. The I hooked it up with an IBACTION I defined in my class. This method does nothing (!) by the way.

Anyway, as soon as I click the button, the App crashes, with "EXC_BAD_ACCESS".

I am surely not overreleasing anything, as far as I can see, that is. What is wrong there?

Any clues?

This is my console log:

Loading program into debugger…
sharedlibrary apply-load-rules all
Program loaded.
target remote-mobile /tmp/.XcodeGDBRemote-148-79
Switching to remote-macosx protocol
mem 0x1000 0x3fffffff cache
mem 0x40000000 0xffffffff none
mem 0x00000000 0x0fff none
run
Running…
[Switching to thread 11779]
[Switching to thread 11779]
(gdb) continue
2010-01-15 09:16:34.800 FlightControl1[1899:207] Table loaded
2010-01-15 09:16:35.200 FlightControl1[1899:207] 23
2010-01-15 09:16:35.350 FlightControl1[1899:207] debug
Program received signal:  “EXC_BAD_ACCESS”.
(gdb) 

This is what I get, after I went up the stack:

#0  0x31ec3ebc in objc_msgSend ()
#1  0x33605784 in -[UIApplication sendAction:to:from:forEvent:] ()
#2  0x336056ec in -[UIApplication sendAction:toTarget:fromSender:forEvent:] ()
#3  0x336056b4 in -[UIControl sendAction:to:forEvent:] ()
#4  0x3360530c in -[UIControl(Internal) _sendActionsForEvents:withEvent:] ()
#5  0x33605f8c in -[UIControl touchesEnded:withEvent:] ()
#6  0x335fd9ac in _UIGestureRecognizerUpdateObserver ()
#7  0x30da1830 in __CFRunLoopDoObservers ()
#8  0x30de9346 in CFRunLoopRunSpecific ()
#9  0x30de8c1e in CFRunLoopRunInMode ()
#10 0x332e7374 in GSEventRunModal ()
#11 0x335adc30 in -[UIApplication _run] ()
#12 0x335ac230 in UIApplicationMain ()
#13 0x000027a8 in main (argc=1, argv=0x2ffff4d8) at /Users/SomePath/main.m:14
like image 348
Icky Avatar asked Jan 15 '10 08:01

Icky


2 Answers

I was tortured by this for a few hours as well. It turned out to be a memory problem as expected. The controller acting as the target for the button was deallocated. It was the root controller of a navigation controller whose view was added directly to the window. My code looked like this:

MyController *myController = [[MyController new] autorelease];
UINavigationController* navController = 
    [[[UINavigationController alloc] initWithRootViewController:myController] autorelease];
[window addSubview:navController.view];

My assumption was that myController would be retained when it's passed as the root controller of the UINavigationController, but that turned out to be wrong. The solution was to assign the controller to a local variable and release it in dealloc. The interface of the object containing the above code should have:

...
@property (retain, nonatomic) MyController *myController;
...

And the implementation:

self.myController = [[MyController new] autorelease];
UINavigationController* navController = 
    [[[UINavigationController alloc] initWithRootViewController:myController] autorelease];
[window addSubview:navController.view];

...

- (void)dealloc {
    [self.myController release];
    ...
    [super dealloc];
}
like image 145
gammal Avatar answered Oct 25 '22 00:10

gammal


As gammal and others pointed out this is a memory problem. It is to do with the controller reference falling out of scope and so its memory is deallocated.

If you initiate the controller like this:

MyController* controller = [[MyController alloc] initWithNibName:@"MyNib" bundle:nil];
[self.view addSubview:controller.view];

You will be fine if you are not using ARC, because the reference won't be deallocated until it is manually released. So I have had this problem when upgrading projects to use ARC.

If you initiate the controller as autorelease, or are using ARC then as soon as the scope that controller exists in ends, the garbage collector will deallocate the controller, and button press events will cause bad memory exceptions.

The way to resolve this is to keep the reference alive, so declare it on the interface, or if it needs external access as a property.

@interface MyParentController : UIView {
@private
    MyController* controller;
}

Then add it like:

controller = [[MyController alloc] initWithNibName:@"MyNib" bundle:nil];
[self.view addSubview:controller.view];

If you do want it the memory to be collected later, just set the value to nil.

like image 20
OnlyJoe Avatar answered Oct 25 '22 00:10

OnlyJoe