Demystifying iOS Application Crash Logs
- 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?
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, but after the app is in the App Store, some users report crashes!
If you’re anything like me, you want your app to be A+. So you go back to your code to fix the crashes… but where do you look?
This is when iOS crash logs come in handy. In most cases, you’ll get very detailed and useful information about the cause of the crash, like feedback from a good teacher.
In this tutorial, you’ll learn about some common crash log scenarios, as well as how to acquire crash logs from development devices and iTunes Connect. You will learn about symbolication, and tracing back from log to code. You will also debug an application that can crash in certain situations.
OK, let’s get crashing!
What Is A Crash Log, and Where Do I Get One?
When an application crashes on an iOS device, the operating system creates a crash report or a crash log. The report is stored on the device.
You can find a lot of useful information in a crash log, including the conditions under which the application terminated. Usually, there is a complete stack trace of each executing thread, so you can see what was happening in every thread at the time of the crash, and identify the thread where the crash occurred.
There are many ways to get a crash log from a device.
A device that is synced with iTunes stores its crash logs on the machine. Depending on the OS, here are the locations where you can find them:
Mac OS X:
C:\Documents and Settings\<USERNAME>\Application Data\Apple Computer\Logs\CrashReporter\MobileDevice\<DEVICE_NAME>
Windows Vista or 7:
When your users experience a crash, you can instruct them to sync their device with iTunes, go to one of the above locations (depending on their OS), download the crash logs and email them to you.
You want any crash logs your users generate. The more crash logs you have, the better equipped you are to find and diagnose weaknesses in your app!
Also, you can easily get the crash reports for your devices via Xcode, if you have it installed. To do this, connect the iOS device to your computer and open Xcode. From the menu bar, select Window, then Organizer (the shortcut is Shift-CMD-2).
In the Organizer window, go to the Devices tab. On the left-hand side navigation pane, look for Device Logs, as shown in the image below:
As you can see in the screenshot, there are multiple Device Logs items. The Device Logs under LIBRARY contain all the logs from all devices you own (or have connected to Xcode). The Device Logs entries under each device are for that particular device.
Once your app is submitted, you can also get crash logs from your users using iTunes Connect. To do this, simply sign in to your iTunes Connect account, navigate to Manage Your Applications, click on the app you want crash logs for, click on the View Details button below the icon, and click on Crash Reports in the right-hand side pane in the Links section.
If there are no crash logs, try clicking on the Refresh button. If you haven’t sold many copies of your app, or if it has been available only for a short time, chances are that you don’t have any crash logs in your iTunes Connect account.
If you did have any crash logs in iTunes Connect, you would see something like this:
Sometimes you won’t see anything in here despite your users reporting a crash. In that case, it’s best to ask them to send you the crash logs if possible.
What Generates a Crash Log?
There are two main situations that can result in a crash log:
- Your app violates OS policies.
- There are bugs in your app.
iOS policy violations include things such as watchdog timeout at the time of launch, resume, suspend and quit; user force-quit; and low memory termination. Let’s go over these in more detail.
As you’re probably aware, since iOS 4.x, most of the time when you quit an iOS app, the app isn’t terminated – instead, it’s sent to the background.
However, there are times when the OS will terminate your app and generate a crash log if the app didn’t respond fast enough. These events correspond with the implementation of the following UIApplicationDelegate methods:
In all of the above methods, the app gets a limited amount of time to finish its processing. If the app takes too long, the OS will terminate the app.
Note: This can easily happen to you if you aren’t performing long running operations (like network access) on background threads. For information on how to avoid this, check out our Grand Central Dispatch and NSOperations tutorials.
iOS 4.x supports multitasking. If an app blocks the UI and stops responding, the user can double-tap the Home button from the Home screen and terminate the app. In this case, the OS generates a crash log.
Note: You may have noticed that when you double-tap the Home button, you also get a list of all the applications you’ve run in the past. Those apps are not necessarily running, nor are they necessarily suspended.
Usually an app gets about 10 minutes to stay in the background once the user hits the Home button, and then it gets terminated automatically by the OS. So the list of apps that you see by double-tapping the Home button is only a list of past app runs. Deleting the icons for those apps does not generate any crash logs.
Low Memory Termination
When subclassing UIViewController, you may have noticed the didReceiveMemoryWarning method.
Any app that is running in the foreground has the highest priority in terms of accessing and using memory. However, that does not mean the app gets all the available memory on the device – each app gets a portion of the available memory.
When total memory consumption hits a certain level, the OS sends out a UIApplicationDidReceiveMemoryWarningNotification notification. At the same time, didReceiveMemoryWarning is invoked for the app.
At this point, so that your app continues to run properly, the OS begins terminating apps in the background to free some memory. Once all background apps are terminated, if your app still needs more memory, the OS terminates your app and generates a crash log.
The OS does not generate a crash log for the background apps that were terminated under this circumstance.
Note: Per Apple documentation, Xcode does not add low memory logs automatically. You have to obtain them manually, as described above. However, in my personal experience using Xcode 4.5.2, low memory crash logs were imported automatically with “Process” and “Type” listed as unknown.
It is also worth mentioning that allocating a big chunk of memory in a very short period of time puts a strain on the system memory — even if for a fraction of a second. This, too, can result in memory warning notifications.
Bugs in the Application
As you can imagine, these cause the majority of app crashes, and hence, are behind the generation of most crash logs. Bugs come in seemingly endless varieties.
Later on in this tutorial, you will confront some actual crash logs from a buggy application, and use your powers of deduction to find the culprits and apply some fixes!