My App Crashed, Now What?

In this tutorial, you’ll learn what makes your app crash and how to fix it when it does. By Ehab Amer.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Proving Your Case

Don’t take this as a fact; question it and make sure that’s really what caused the crash. When you fix a crash, you don’t want to do it by trial and error. You want to be 110% sure you’re fixing what’s broken.

To test your theory, type this command in the Console Log:

po Int(item)

The po command you entered before the expression stands for print object, which is an LLDB command to print the description of an object. You can also use p, but the result in the console will look slightly different.

The console output will be nil:

Console output for the expression

So Int(item) is nil, and when you execute po Int(item)! you get some additional information.

Console Log with an exception description

This result is the same as the error written on the crash, so you’re definitely right about the source of the crash.

But wait! How does it work for the other values?

Add a breakpoint on the same line that caused the crash and restart the app. Remember to write ,two before you calculate the sum.

Breakpoint stop on calculateSum(items:)

The value of item on the breakpoint is 4 and the result of Int(item) gives a value instead of nil.

console outputs

Finding the Right Solution

Int(_:) worked when the value of item is 4, but it won’t work when it’s two. In other words, it works when the value is a string with numeric digits, but not with alphabetical letters, even when they form the name of the number.

To fix this crash, replace the following line of code in calculateSum(items:):

finalValue += Int(item)!

With this block of code:

if let intValue = Int(item) {
  finalValue += intValue
}

The code above checks that the result of Int(item) isn’t nil before using it, which makes it safe from crashes.

Disable the breakpoint by clicking on the blue arrow and it will become semi-transparent blue. Build and run and add any kind of text you want in the text field after the numbers.

Dummy text entered in the text field

It doesn’t crash anymore, but is it completely fixed? Instead of adding the numbers, delete the last one and try again.

Removing the last number from the list

The app crashed again in ForceUnwrappingViewController.swift on line 58.

The crash line in Xcode.

The relevant message from the log is:

Could not cast value of type 'Swift.String' (0x7fff879c3f88) to 'Swift.Int' (0x7fff879c1e48).

The crashing line is forcing a cast on result as an Int, while the value you provided is a String. That means valueToShow is nil and when you force unwrap it, the app crashes, similar to the crash above that you have already fixed.

calculateSum(items:) will only show the sum if the total is more than 100. Otherwise, the message should be “Sum is too low”.

This is a straightforward fix. Replace the code inside showResult(result:) with this block of code:

if let intValue = result as? Int {
  sumLabel.text = "\(intValue)"
} else if let stringValue = result as? String {
  sumLabel.text = stringValue
}

Here, you check if you can cast result to an Int, then create a String of its value and add it to the label. You use the value as it is if you can cast it to a String.

Build and run. You’ll see the error message, “Sum is too low” when the total is below 100.

Message appearing properly when sum is below 100

Exhibit B: Weak Grip — Weak References

The second crash you’re going to fix involves an unusual way of showing and hiding views.

Second screen, weak references.

The Weak References screen is a simple form with two steps, where the second step is only active if the answer to the first question is “yes.”

Note: There are many ways you can achieve the same result other than the one shown in this app. The intention is to show a made-up scenario that causes a crash, not to make a form that works well.

When you turn off the switch, the second question disappears, but when you turn it on again… there’s the crash.

Crashing line for the second screen

The app crashed in WeakReferencesViewController.swift line 37.

WeakReferencesViewController has three items:

  1. An IBOutlet to the stackView.
  2. An IBOutlet to the secondQuestionView.
  3. An IBAction to switchValueChanged(_:), where you change the value of the switch to remove the secondQuestionView or to add it back at the bottom of the stackView.

There are two ways to figure out why Xcode is showing nil: Explore the values from the Variables View or check the values of the two variables found on the crashing line from the Console Log.

Values shown in Variables View and Console Log

From what the debugger output says, the value of secondQuestionView is nil, but why? Add a breakpoint on the first line of switchValueChanged(_:) and restart the app to start investigating.

Build and run.

Breakpoint on first line, both values are present.

secondQuestionView isn’t nil when you turn off the switch. However, when you turn it on again after the view disappears, it’s already nil.

Understanding the Crash

The reason for that is because of the reference chain in UIKit. Each view has a strong reference to the subviews presented inside it. As long as secondQuestionView is in the on-screen view hierarchy, something will be holding a strong reference to it.

So when you removed the secondQuestionView from its superview, you broke that tie. And looking at the IBOutlet definition of secondQuestionView, you’ll find it’s marked as weak. Thus, it deallocated from memory and its reference changed to nil since no one was holding it to prevent it from doing so.

Once you remove the weak keyword from the secondQuestionView declaration, the crash will disappear. You can do the same for stackView as a precaution, but it will have no effect on the crash since you never remove the stackView from the superview.

Remove the weak keywords, then build and run to try the scenario again.

Second view disappears and appears normally without crashing

You’ll see that the form works fine now. The view appears and disappears as required.

Exhibit C: Unexpected Updates — Invalid Table Updates

The third crash is slightly different from the previous ones. It’s more of a data mismatch.

Open the third item, called Invalid Table Updates, on the gallery screen to start your investigation.

Invalid Table Updates screen

This screen has a table view with four cells. Each cell has its number written on it. There’s also a small button in the top-right corner to add more cells.

Go ahead and press that button. As you may have expected, there’s a crash. But… which line is crashing? And what’s all that in the log?

Crash line is the declaration of AppDelegate and crash log is long

Xcode stopped in AppDelegate.swift on line 32.

Add an exception breakpoint to your project, then build and run to see the difference.

Third screen crash with exception breakpoint added

This time, Xcode stopped in InvalidTableUpdatesViewController.swift on line 37. The log is empty and has no information provided because the breakpoint stopped right before the exception happened. This is a different kind of crash than the previous ones.

When you press the Continue button, Xcode will return to the class declaration line in AppDelegate.swift and the log will have the crash information.

Continue execution button

The log contains information about the crash and the stack trace information for when the crash happened. Most of the time, you won’t need the stack trace information when you are debugging from Xcode and have your exception breakpoint enabled. Take a look at the crash information.

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to insert row 4 into section 0, but there are only 4 rows in section 0 after the update.