Swift has language constructs that allow you to specify your program’s expectations. If these expectations are not met at runtime, the program will be terminated. For example, indexing into an array implicitly expresses an expectation that the index is in bounds:
// Program will terminate if 'index' less than 0 or greater than 'array.count - 1'. let element = array[index]
Another common operation that will terminate the program on failure is a forced unwrap of an optional:
// Program will terminate if 'self.navigationController' is nil. let nc = self.navigationController!
Preconditions are yet another example:
// Program will terminate if 'index' is less or equal to 0. precondition(index > 0, "Index must be greater than zero.")
When the expectations are incorrect or when there’s a bug in the code, Swift guarantees that the program will trap. Especially during development it’s common that some precondition isn’t met, the program terminates and the debugger will show that. However, prior to Xcode 9.1 (currently available as a beta), the debugger displayed these situations just as any other type of crash — usually as
EXC_BREAKPOINT (which are the low-level Mach exceptions types).
This has been a source of confusion for both beginners and seasoned developers. In Xcode 9.1 the display of fatal errors is significantly improved. When running under the debugger, Xcode will now show the failure reason in the editor where the trap occurred:
Many events that trigger a runtime trap are covered, including:
- forced unwrapping
- forced-try expressions (
try!) producing an error
- out-of-bounds indexing into arrays
- precondition failures
- assertion failures
Note that this improved experience is only available when the app’s entry point is written in Swift (i.e. your app delegate with the
Xcode 9.1 can be downloaded from developer.apple.com (currently a pre-release version, an official release will be available later this year).