Demystifying iOS Application Crash Logs
This is a blog post by Soheil Moayedi Azarpour, an independent iOS developer. You can also find him on Google+. Have you ever had the following experience as an app developer? Before you submit your app, you perform a lot of testing to make sure your app runs flawlessly. It works fine on your device, […] By Soheil Azarpour.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Demystifying iOS Application Crash Logs
50 mins
- What Is A Crash Log, and Where Do I Get One?
- What Generates a Crash Log?
- A Sample Crash Log
- Demystification with Symbolication
- Low Memory Crashes
- Exception Codes
- Swimming Time!
- Scenario 1: Bad Code for Breakfast
- Scenario 2: Button FUBAR
- Scenario 3: Another Bug On the Table
- Scenario 4: Leggo Those Licks!
- Where to Go From Here?
Scenario 1: Bad Code for Breakfast
From a user email: “Man, your app is a piece of junk! I downloaded it on my iPod Touch, iPhone and my son’s iPod Touch. On all devices, it crashed before running on the first try…”
Another email says, “I downloaded your app and it crashed. Very unhappy…”
Another email is more specific: “I can’t get your app to run. I downloaded it on all of my devices and on my wife’s. On all of them, it crashed on the first launch…”
OK, don’t take this lying down! Do any of these comments give you a hint? Take a look at the crash log:
Incident Identifier: 85833DBA-3DF7-43EE-AF80-4E5C51091F42
CrashReporter Key: 5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model: iPhone4,1
Process: Rage Masters [20067]
Path: /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters
Identifier: Rage Masters
Version: ??? (???)
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2012-11-03 13:37:31.148 -0400
OS Version: iOS 6.0 (10A403)
Report Version: 104
Exception Type: 00000020
Exception Codes: 0x000000008badf00d
Highlighted Thread: 0
Application Specific Information:
Soheil-Azarpour.Rage-Masters failed to launch in time
Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU
Elapsed application CPU time (seconds): 3.840, 10% CPU
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0:
0 libsystem_kernel.dylib 0x327f2eb4 mach_msg_trap + 20
1 libsystem_kernel.dylib 0x327f3048 mach_msg + 36
2 CoreFoundation 0x36bd4040 __CFRunLoopServiceMachPort + 124
3 CoreFoundation 0x36bd2d9e __CFRunLoopRun + 878
4 CoreFoundation 0x36b45eb8 CFRunLoopRunSpecific + 352
5 CoreFoundation 0x36b45d44 CFRunLoopRunInMode + 100
6 CFNetwork 0x32ac343e CFURLConnectionSendSynchronousRequest + 330
7 Foundation 0x346e69ba +[NSURLConnection sendSynchronousRequest:returningResponse:error:] + 242
8 Rage Masters 0x000ea1c4 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:36)
9 UIKit 0x37f30ad4 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 248
10 UIKit 0x37f3065e -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1186
11 UIKit 0x37f28846 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 694
12 UIKit 0x37ed0c3c -[UIApplication handleEvent:withNewEvent:] + 1000
13 UIKit 0x37ed06d0 -[UIApplication sendEvent:] + 68
14 UIKit 0x37ed011e _UIApplicationHandleEvent + 6150
15 GraphicsServices 0x370835a0 _PurpleEventCallback + 588
16 GraphicsServices 0x370831ce PurpleEventCallback + 30
17 CoreFoundation 0x36bd4170 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 32
18 CoreFoundation 0x36bd4112 __CFRunLoopDoSource1 + 134
19 CoreFoundation 0x36bd2f94 __CFRunLoopRun + 1380
20 CoreFoundation 0x36b45eb8 CFRunLoopRunSpecific + 352
21 CoreFoundation 0x36b45d44 CFRunLoopRunInMode + 100
22 UIKit 0x37f27480 -[UIApplication _run] + 664
23 UIKit 0x37f242fc UIApplicationMain + 1116
24 Rage Masters 0x000ea004 main (main.m:16)
25 libdyld.dylib 0x3b630b1c start + 0
Did you find the problem? The exception code is 0x000000008badf00d, and right after that, the report says:
Application Specific Information:
Soheil-Azarpour.Rage-Masters failed to launch in time
Elapsed total CPU time (seconds): 8.030 (user 8.030, system 0.000), 20% CPU
Elapsed application CPU time (seconds): 3.840, 10% CPU
This means that the app failed to launch in time, and the iOS watchdog terminated the app. Cool! You found the reason, but why (and more importantly, where) is it happening?
Look further down in the log. The convention is to read the backtrace log from the bottom up. The lowest frame (frame 25: libdyld.dylib) is the first call, then frame 24, Rage Masters, main (main.m:16) is called from there, and so on.
You are interested in frames that are related to your app’s code. So ignore system libraries and frameworks. The next line relevant to your code is:
8 Rage Masters 0x0009f244 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35)
The app failed in application:didFinishLaunchingWithOptions:, on line 35 in RMAppDelegate (RMAppDelegate.m:35). Open Xcode and take a look at that line:
NSData *directoryData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
Yep, there it is! A synchronous call to a web service?! On the main thread?! In application:didFinishLaunchingWithOptions:?!! Who wrote this code?!
Anyway, it’s your job to fix it. This call should be asynchronous and, even better, executed from another part of the application, after application:didFinishLaunchingWithOptions: has returned YES.
It might require more extensive changes to move the call elsewhere. So for the moment, just take care of the code so that it doesn’t crash. You can always go back and implement a better design later. Replace the line of offending code from above (and the three lines following it) with an asynchronous version:
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error)
{
NSURL *cacheDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSUserDirectory inDomains:NSCachesDirectory] lastObject];
NSURL *filePath = [NSURL URLWithString:kDirectoryFile relativeToURL:cacheDirectory];
[data writeToFile:[filePath absoluteString] atomically:YES];
}];
Scenario 2: Button FUBAR
A user writes: “I can’t bookmark a rage master as my favorite. When I try to, the app crashes…”
Another user says, “Bookmarking doesn’t work… I go to detail info, tap on bookmark button and BOOM!”
The above complaints don’t say much, and there could be any number of causes for the issue they’ve identified. Take a look at the crash log:
Incident Identifier: 3AAA63CC-3088-41CC-84D9-82FE03F9F354
CrashReporter Key: 5a56599d836c4f867f6eec76afee451bf9ae5f31
Hardware Model: iPhone4,1
Process: Rage Masters [20090]
Path: /var/mobile/Applications/B2121A89-3D1F-4E61-BB18-5511E1DC150F/Rage Masters.app/Rage Masters
Identifier: Rage Masters
Version: ??? (???)
Code Type: ARM (Native)
Parent Process: launchd [1]
Date/Time: 2012-11-03 13:39:00.081 -0400
OS Version: iOS 6.0 (10A403)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Crashed Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x36bff29e __exceptionPreprocess + 158
1 libobjc.A.dylib 0x34f0f97a objc_exception_throw + 26
2 CoreFoundation 0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166
3 CoreFoundation 0x36c0152c ___forwarding___ + 388
4 CoreFoundation 0x36b58f64 _CF_forwarding_prep_0 + 20
5 UIKit 0x37fbb0a8 -[UIApplication sendAction:to:from:forEvent:] + 68
6 UIKit 0x37fbb05a -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 26
7 UIKit 0x37fbb038 -[UIControl sendAction:to:forEvent:] + 40
8 UIKit 0x37fba8ee -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 498
9 UIKit 0x37fbade4 -[UIControl touchesEnded:withEvent:] + 484
10 UIKit 0x37ee35f4 -[UIWindow _sendTouchesForEvent:] + 520
11 UIKit 0x37ed0804 -[UIApplication sendEvent:] + 376
12 UIKit 0x37ed011e _UIApplicationHandleEvent + 6150
13 GraphicsServices 0x3708359e _PurpleEventCallback + 586
14 GraphicsServices 0x370831ce PurpleEventCallback + 30
15 CoreFoundation 0x36bd416e __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 30
16 CoreFoundation 0x36bd4112 __CFRunLoopDoSource1 + 134
17 CoreFoundation 0x36bd2f94 __CFRunLoopRun + 1380
18 CoreFoundation 0x36b45eb8 CFRunLoopRunSpecific + 352
19 CoreFoundation 0x36b45d44 CFRunLoopRunInMode + 100
20 GraphicsServices 0x370822e6 GSEventRunModal + 70
21 UIKit 0x37f242fc UIApplicationMain + 1116
22 Rage Masters 0x000ca004 main (main.m:16)
23 libdyld.dylib 0x3b630b1c start + 0
The exception code is a SIGABRT. Usually, a SIGABRT exception is raised when an object receives an unimplemented message. Or to put it in simpler terms, there’s a call for a nonexistent method on an object.
Usually this won’t happen, since if you call method “foo” on object “bar”, the compiler will throw an error if the method “foo” doesn’t exist. But when you indirectly call a method using a selector, the compiler might not be able to determine whether or not the method exists on the object.
Back to the crash log. It indicates that the crashed thread is 0. This means that you’re probably looking at a situation where a method was called on an object on the main thread, where the object did not implement the method.
If you continue reading the backtrace log, you see that the only call related to your code is frame 22, main.m:16. That doesn’t help much. :[
Keep going up the framework calls, and there it is:
2 CoreFoundation 0x36c02e02 -[NSObject(NSObject) doesNotRecognizeSelector:] + 166
That isn’t your code. But at least it confirms that there was a call to an unimplemented method on an object.
Go to RMDetailViewController.m, since that’s where the bookmark button is implemented. Find the code that bookmarks the rage master:
-(IBAction)bookmarkButtonPressed {
self.master.isBookmarked = !self.master.isBookmarked;
// Update shared bookmarks
if (self.master.isBookmarked)
[[RMBookmarks sharedBookmarks] bookmarkMaster:self.master];
else
[[RMBookmarks sharedBookmarks] unbookmarkMaster:self.master];
// Update UI
[self updateBookmarkImage];
}
That looks OK, so check the storyboard (XIB file) and make sure that the button is hooked up correctly.
There it is! In MainStoryboard.storyboard, the button refers to bookmarkButtonPressed: instead of bookmarkButtonPressed (note the final colon indicating that the method expects a parameter). To fix this, replace the signature of the method above with this:
-(IBAction)bookmarkButtonPressed:(id)sender {
// Remain unchanged...
}
Of course, you could also simply remove the incorrect connection in the XIB file and reconnect to the method, so that the method signature is correct in the XIB file. Either way works.
And that’s another crash fixed. You’re getting pretty good at this. :]