Search code examples
iosswiftxcode8xcode-instrumentsnszombie

EXC_BAD_ACCESS on long press; no zombie activity


EDIT: I have determined that the following happens only on an iPad Retina simulator and on my iPad Mini 3 test device. It happens 100% of the time on those targets and never on any other iPad or iPhone simulator (iPad Air/Air 2; iPad Pro; iPhone 5 through 7 Plus). I don't have any other devices for testing.


I have an app written in Swift that displays a UITableView where I have added a UILongPressGestureRecognizer to a custom view inside each cell. The app runs fine until I long-press on a row, at which point the app stops with

Thread 1: EXC_BAD_ACCESS (code=1, address=0xd08600b6)

(The address varies wildly and seems pretty random. Sometimes it's 0x0.) When the crash occurs, no output appears in the debug console. XCode itself opens to the first line of the class declaration for my app delegate.

I put a breakpoint at the first line of my long-press event handler method but the app crashes before the breakpoint is hit. I also added an exception breakpoint, but it does not catch the problem either.

I've enabled zombie objects in the scheme, but nothing shows up. I've tried running the app using Instruments and the zombies template; the app simply stops and Instruments doesn't flag any zombie activity. XCode's Analyze reports no problems.

I don't know how it can be relevant, but this problem is new since I first archived the app in preparation for distribution to testers. Before that, the app was working flawlessly on simulators and on a test device. The problem first showed up the first time I installed and ran the distribution .ipa file on a device. I then went back to simulator and found the same behavior. I've cleaned the project, cleaned the build folder, rebooted my development machine, and done everything I can think of to run in a pristine state. No difference.

I'm at a loss for how to make progress in tracking this down. Any suggestions would be greatly appreciated.

Further Information

It appears that the crash is happening inside the #selector object that was passed to the UILongPressGestureRecognizer initializer. Here's the call stack from the Debug navigator pane:

#0 0x006e7295 in objc_retain ()
#1 0x0007529f in @objc TikkunRowView.onLongPress(sender : UILongPressGestureRecognizer, forEvent : UIEvent) -> () ()
#2 0x01cc6d3b in -[UIGestureRecognizerTarget _sendActionWithGestureRecognizer:] ()
#3 0x01ccf75e in _UIGestureRecognizerSendTargetActions ()
#4 0x01cccdee in _UIGestureRecognizerSendActions ()
#5 0x01ccbca8 in -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] ()
#6 0x01cb6670 in _UIGestureEnvironmentUpdate ()

And here's the code in #1 above where the crash occurs (the calll at offset <+42>):

Tikkun Sample`@objc TikkunRowView.onLongPress(sender : UILongPressGestureRecognizer, forEvent : UIEvent) -> ():
    0x60270 <+0>:   pushl  %ebp
    0x60271 <+1>:   movl   %esp, %ebp
    0x60273 <+3>:   pushl  %esi
    0x60274 <+4>:   subl   $0x24, %esp
    0x60277 <+7>:   movl   0x14(%ebp), %eax
    0x6027a <+10>:  movl   0x10(%ebp), %ecx
    0x6027d <+13>:  movl   0x8(%ebp), %edx
    0x60280 <+16>:  movl   %ecx, (%esp)
    0x60283 <+19>:  movl   %ecx, -0x8(%ebp)
    0x60286 <+22>:  movl   %edx, -0xc(%ebp)
    0x60289 <+25>:  movl   %eax, -0x10(%ebp)
    0x6028c <+28>:  calll  0x7c9ec                   ; symbol stub for: objc_retain
    0x60291 <+33>:  movl   -0x10(%ebp), %ecx
    0x60294 <+36>:  movl   %ecx, (%esp)
    0x60297 <+39>:  movl   %eax, -0x14(%ebp)
    0x6029a <+42>:  calll  0x7c9ec                   ; symbol stub for: objc_retain
>>  0x6029f <+47>:  movl   -0xc(%ebp), %ecx << CRASH HAPPENS WITH THIS LINE HIGHLIGHTED
    0x602a2 <+50>:  movl   %ecx, (%esp)
    0x602a5 <+53>:  movl   %eax, -0x18(%ebp)
    0x602a8 <+56>:  calll  0x7c9ec                   ; symbol stub for: objc_retain
    0x602ad <+61>:  movl   -0x8(%ebp), %ecx
    0x602b0 <+64>:  movl   %ecx, (%esp)
    0x602b3 <+67>:  movl   -0x10(%ebp), %edx
    0x602b6 <+70>:  movl   %edx, 0x4(%esp)
    0x602ba <+74>:  movl   -0xc(%ebp), %esi
    0x602bd <+77>:  movl   %esi, 0x8(%esp)
    0x602c1 <+81>:  movl   %eax, -0x1c(%ebp)
    0x602c4 <+84>:  calll  0x5fd40                   ; Tikkun_Sample.TikkunRowView.onLongPress (sender : __ObjC.UILongPressGestureRecognizer, forEvent : __ObjC.UIEvent) -> () at TikkunRowView.swift:128
    0x602c9 <+89>:  movl   -0xc(%ebp), %eax
    0x602cc <+92>:  movl   %eax, (%esp)
    0x602cf <+95>:  calll  0x7c9e6                   ; symbol stub for: objc_release
    0x602d4 <+100>: addl   $0x24, %esp
    0x602d7 <+103>: popl   %esi
    0x602d8 <+104>: popl   %ebp
    0x602d9 <+105>: retl   

I'm no expert on reading this stuff, but it looks like the crash is happening in compiler-generated code that is supposed to dispatch to my event handler method. I have no idea what objects this code is checking before getting to calling my code (at offset <+84>). Here's the code I use to construct the gesture recognizer:

let g = UILongPressGestureRecognizer(target: self, action: #selector(TikkunRowView.onLongPress(sender:forEvent:)))

Solution

  • I don't know why the console didn't give you any detail error message. (It should!) But looking at your code, it's obviously due to the wrong signature of the gesture action callback. The following is quoted from the api doc.

    The action methods invoked must conform to one of the following signatures:
    - (void)handleGesture;
    - (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer;