UIScrollView EXC_BAD_ACCESS crash in iOS SDK

20,777

Solution 1

The UIScrollView on stack frame #1 probably wants to inform its delegate about the animation ending, but the delegate is gone at that point. Setting NSZombieEnabled would probably confirm this.

Delegates are not retained, so this is a common error in Cocoa and Cocoa Touch. Look for delegates on UIScrollView or UITableView in your code and try to find out which one might be released before its time.

Solution 2

I just worked through this problem myself.

I had an issue where:

  • A scrollview delegate was wired to a UIViewController
  • The scrollview began animating
  • The delegate went away and dealloc was called.

The problem was the scrollview delegate messages were firing on a new-deallocated object, and the crash logs were a bit confusing as they were pointing to nonsensical object references.

The fix was to set the scrollview delegate to nil as the first line of my view controller dealloc method.

Hope this helps someone else!

Solution 3

For completeness I'm adding this stack trace (iOS 6) for those who may encounter the same problem but with a little bit different implementation and the exact steps to reproduce the problem.

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x71f05631
Crashed Thread:  0

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x3919b5d0 objc_msgSend + 1
1   UIKit                           0x33421830 -[UIScrollView(UIScrollViewInternal) _delegateScrollViewAnimationEnded] + 48
2   UIKit                           0x334217ba -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded:finished:] + 130
3   UIKit                           0x334216a4 -[UIAnimator stopAnimation:] + 460

This is happening on iOS 6 and started to occur when I implemented the UIScrollViewDelegate method:

" -(void)scrollViewDidEndDecelerating:(UITableView *)tableView" 
and made a call to:
"[tableView scrollToRowAtIndexPath: indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];".  

The problem occurred when the animation started and I pressed the "Back" button and my view controller was popped off before the animation completed.

When reproducing you must be sure to press the "Back" button after the the animation starts but before it completes. It took my a few tries. I tried to recreate the problem by programmatically popping the view controller off but was not able to reproduce it. I had to use the "Back" button. I had been simply calling [myTableView release] in the dealloc. The solution was as described here to set both of these properties to nil:

self.myTableView.delegate = nil;
self.myTableView = nil;

Solution 4

At first, delegates should be of weak/assign type. But event in this case there is a very common subtle obstacle driven by scroll animations. If you use animated content offset changes for your ScrollViews you strongly need to set its delegate to nil at dealloc method.

Otherwise you will get the following

[YourViewController respondsToSelector:]: message sent to deallocated instance

The very common example:

1. _tableView is ivar of YourViewController
2. _tableView.delegate = self;
3. - (void)scrollViewDidScroll:(UIScrollView *)scrollView is implemented at YourViewController
4. at some point you call [_tableView scrollToRowAtIndexPath:indexPath 
   atScrollPosition:UITableViewScrollPositionBottom animated:YES];
   or [_tableView setContentOffset:CGPoint animated:YES]
   and try to close YourViewController

The _tableView is retained by CoreAnimation, but YourViewController is deallocated!

Solution 5

My guess would be that the scrollview's delegate is set to an object that has been deallocated. Try settings all the delegates of child objects to nil in your dealloc methods.

Share:
20,777
BP.
Author by

BP.

My aspirations in life are to meet Frank Zappa, see the Leafs win the Stanley Cup, and write a killer iPhone app. Yes, my life is all about the pursuit of what is impossible, unlikely, and incredibly challenging.

Updated on May 05, 2020

Comments

  • BP.
    BP. about 4 years

    I have an iPhone SDK application that has several views that appear and disappear as the user creates content. After using the application on a device for a while, I get the following crash:

    Program received signal:  “EXC_BAD_ACCESS”.
    (gdb) backtrace
    #0  0x33369ebc in objc_msgSend ()
    #1  0x320e5248 in -[UIScrollView(UIScrollViewInternal) _scrollViewAnimationEnded] ()
    #2  0x338b4a14 in -[NSObject performSelector:withObject:] ()
    #3  0x320e5098 in -[UIAnimator stopAnimation:] ()
    #4  0x320e4b7c in -[UIAnimator(Static) _advance:] ()
    #5  0x320e4a34 in LCDHeartbeatCallback ()
    #6  0x34350e60 in HeartbeatVBLCallback ()
    #7  0x332e91c0 in IOMobileFramebufferNotifyFunc ()
    #8  0x316532f8 in ?? ()
    #9  0x33866b50 in __CFMachPortPerform ()
    #10 0x338ae52a in CFRunLoopRunSpecific ()
    #11 0x338adc1e in CFRunLoopRunInMode ()
    #12 0x3434e1c8 in GSEventRunModal ()
    #13 0x32002c30 in -[UIApplication _run] ()
    #14 0x32001230 in UIApplicationMain ()
    #15 0x00002ff8 in main (argc=1, argv=0x2ffff550) at /Developer/svn/MyCompany/iPhone/MyApplication/Other Sources/main.m:14
    

    As you can see from the trace, the only mention of my code in there is the call to main.

    I have run Build and Analyze from Xcode, and also set it up to run the clang analyzer on my project from the Terminal, and both of these cannot find any problems in the code. I am using a very recent release version of the iOS SDK (I have not downloaded the 4.1 yet, but the one I am using is the one that was in release right before 4.1).

    Also, I have run the application in Instruments with the Simulator, and the app has no memory leaks.

    I am about to try to use the NSZombieEnabled variable and see if that finds anything, but the problem is that I need to use the application for 30 to 40 minutes or so before it crashes, and I suspect that NSZombieEnabled may not even help me find the issue.

    It seems like the crashes that I have seen is when a modal view calls a delegate in the parent view controller. The parent view controller then does some processing before dismissing the modal view controller. There is some references in the crash to animating and scroll views, but I am not sure what I could be doing to cause those to have problems. Does anyone have any suggestions for things to look for?

    EDIT: I have put the NSZombieEnabled flag into the application, and on the device, it comes up with this message in the console:

    2010-09-11 17:10:33.970 MyApplication[9321:207] *** 
    -[MyViewController respondsToSelector:]: message 
    sent to deallocated instance 0x7489480
    

    As far as I can tell, I am setting the delegates used in the application to nil in the deallocs of all my classes, so I am stuck as to where to look next.

    I tried to use the malloc_history pid address command on this, but it said that it could not find the process, I tried 9321, 9321:207, and 207. Also, if I try to use the MallocStackLogging variable, the program will not run on the device, I get a bunch of malloc: unable to create stack log directory messages in the console and a program crash.

    Oh, and by the way, I can't use the zombies checking in Instruments, since it does not appear to work with a device, and I can't get the same crash to happen in the Simulator.

  • Shaggy Frog
    Shaggy Frog almost 14 years
    +1. To be explicit, delegate properties should always be set to assign and not retain
  • Nikolai Ruhe
    Nikolai Ruhe almost 14 years
    There's always an exception to the rule. See NSURLConnection for a valid reason to retain a delegate.
  • BP.
    BP. almost 14 years
    I do have a UITableView that resides on a UIViewController, and when the app crashes, I believe that it is getting ready to go back to this view controller. However, the delegate for this UITableView is set in Interface Builder, and it is not changed anywhere in the code.
  • Nikolai Ruhe
    Nikolai Ruhe almost 14 years
    This delegate might be the problem. To verify, use NSZombiesEnabled. You have to take care that the delegate lives longer than the UITableView (or the property on the table view is set to nil). Of course, IB is not to blame because it does not handle lifetime. You have to do this in your application logic.
  • Admin
    Admin about 12 years
    You probably have no idea how much trouble you just saved me with this answer, thank you :D
  • derpoliuk
    derpoliuk over 10 years
    Thanx for this answer! Saved me a lot of time
  • mOp
    mOp over 10 years
    Do you have any proof? Made the change, but I am not sure if it will fix the crash.
  • Peter Lapisu
    Peter Lapisu over 10 years
    from my own experience (and exactly the same problem), as some parts of the older API uses assign (instead of the new weak, and therefor hang up with dead pointers) - this is for sure the case if you insert UIRefreshController as a Subview (NEVER DO THAT! UIRefreshController is not meant to be inserted as subview)
  • logixologist
    logixologist about 10 years
    I have a simililar issue, I think... its in the scrollView didScroll delegate method. But its an ARC project now so how could that happen?
  • Avi
    Avi about 9 years
    I followed chips's answer earlier but this makes more sense to me and helps me keep my code clean. Thanks. +1
  • Vee
    Vee about 7 years
    I came across the same bug and suspected that the problem was inserting a UIRefreshController as a subview of a UITableView object. Per Apple documentation, UIRefreshControl should only be used with a UITableViewController but I was dealing with a legacy UIViewController. After further debugging, I figured out that the problem was the app was losing a reference an object created in one of my UITableViewDelegate methods in the UIViewController. All I needed to do was create a property in the UIViewController and set it to that object.