How do I debug a stack trace that doesn't break in my code?

I have seen many stack traces, both while debugging, and from Crashlytics, that have the following type of appearance:


CoreFoundation __exceptionPreprocess + 126

CoreFoundation -[NSException name]

UIKit -[UIView(Hierarchy) _findFirstSubviewWantingToBecomeFirstResponder] + 502

UIKit -[UIView(Hierarchy) _findFirstSubviewWantingToBecomeFirstResponder] + 606

UIKit -[UIView(Hierarchy) _findFirstSubviewWantingToBecomeFirstResponder] + 606

UIKit -[UIView(Hierarchy) _promoteSelfOrDescendantToFirstResponderIfNecessary] + 24

UIKit __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 176

UIKit -[UIView(Hierarchy) _postMovedFromSuperview:] + 426

UIKit -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1608

UIKit -[UIView(Hierarchy) insertSubview:belowSubview:] + 44

UIKit __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke93 + 406

UIKit -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 540

UIKit -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 204

UIKit -[UIViewAnimationState animationDidStop:finished:] + 78

QuartzCore CA::Layer::run_animation_callbacks(void*) + 252

libdispatch.dylib _dispatch_client_callout + 22

libdispatch.dylib _dispatch_main_queue_callback_4CF$VARIANT$mp + 1524

CoreFoundation __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8

CoreFoundation __CFRunLoopRun + 1574

CoreFoundation CFRunLoopRunSpecific + 520

CoreFoundation CFRunLoopRunInMode + 108

GraphicsServices GSEventRunModal + 160

UIKit UIApplicationMain + 144

ChirpEEvent main.m line 14

main libdyld.dylib start + 2


How can I possibly determine what caused this crash? The only break is in main.m.


I run into this a lot, and it is very frustrating. Is there some special debugging switch that I need to throw that will give me better results? How do I debug this when I get it through Crashlytics, or from a customer?


Thanks.

To start you need to find out what the exception says. It seems like your app is doing something to make the view hierarchy grumpy, and the message associated with the exception will help you understand what that ‘something’ is.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks, Quinn. Silly me, I missed that part.


Here's the complaint:


"Fatal Exception: NSGenericException

*** Collection <CALayerArray: 0x167d1f40> was mutated while being enumerated."


I understand that something in the view hierarchy is being improperly mutated. But how do I figure out where/when it is happening? Nothing in the call stack is giving any indication as to where in my code this is occurring.


Looking forward to more enlightenment. :-)


Edit: It is happening on iOS 7 & iOS 9.

Does the crash report include the stack traces of the other threads in your app? What do those show?


I suspect you're accidentally doing GUI manipulations from a background thread. That may have been caught in the crash report, although the background thread may also have had a chance to move on after it did its damage.


Alternatively, do you add or remove views or layers in -canBecomeFocused or something like that?

Oh, you rock. Now we're getting somewhere. Here's another thread:


libsystem_kernel.dylib __semwait_signal + 24

libsystem_c.dylib nanosleep + 172

Foundation +[NSThread sleepForTimeInterval:] + 142

ChirpEEvent A2ZAdsData.m line 88

__24-[A2ZAdsData initAdData] _block_invoke

libdispatch.dylib _dispatch_call_block_and_release + 10

libsystem_pthread.dylib _pthread_wqthread + 1024


Here's the offending code:


self.adRefreshTimeMinutes = 10;

self.adRotateTimeSeconds = 10;

dispatch_queue_t backgroundQueue = dispatch_queue_create("com.a2zEvent.adSyncQueue", 0);

//

[self fetchLocalAdData];

dispatch_async(backgroundQueue, ^{

//

[self fetchRemoteAdData];

while (true) {

[NSThread sleepForTimeInterval:self.adRefreshTimeMinutes * 60];

[self fetchRemoteAdData];

}

});


Several of the crash reports report the same thread with the same code being in the middle of the crash. The bolded line is the offending line, I think. So ... what doesn't iOS like about that code? Is is supposed to be executed on the main thread? That becomes problematic for other reasons.


Thanks for the clue. This is real progress.


Edit: Never mind, I think. I think all that thread is indicating is that it is being executed. I've got a couple of other places where I am invoking sleepForTimeInterval.


Now I'm back to square one. I can't see anything in the other threads.


I am seeing this in a couple of the reports:


Crashed: com.apple.main-thread

SIGABRT ABORT at 0x3b5a41f0


libsystem_kernel.dylib __pthread_kill + 8

libobjc.A.dylib _objc_terminate() + 192

libc++abi.dylib std::__terminate(void (*)()) + 78

libc++abi.dylib __cxa_increment_exception_refcount

UIKit UIApplicationMain + 1136

ChirpEEvent main.m line 14

main


The bolded line is highlighted in the report. Do you know what that means?

Just a guess, the references to animations and UINavigation in the stack trace suggest that something bad is happening while a view controller is being pushed or popped. Those two processes take some time and if the view hierarchy is modified during that time things can go wrong. Usually what I've seen are messages in the console but not actual crashes.


This might happen if you use GCD to make something happen on the main thread from the background. However, since you don't have direct access to the collection being modified it's almost certain that your code is accessing UI code from a background thread. (or there's a bug on Apple's side that you're somehow provoking.)


googling some of the method names in the stack trace will point you to others with possibly related problems.


The bolded line you mention just tells you what you already know. terminate() was called due to the unhandled exception due to the SIGABRT, which is due to the layer collection being modified while being iterated.

How do I debug a stack trace that doesn't break in my code?
 
 
Q