SIGTRAP: Decoding A Cryptic Objective-C + Swift Crash

2017-06-05 aoyuch03ayt

In 2015, Raizlabs switched over to Swift for all iOS development. The move has been rewarding; Swift’s commitment to type safety and optional handling decreased our overall defect and crash rates (and increased developer happiness.)

While this increased safety is awesome for Swift-only apps, it can introduce some hiccups in legacy Objective-C + Swift hybrid apps.

Objective-C + Swift Interoperability

Compared to the vigilant and meticulous Swift compiler, Objective-C is super casual: force cast this to that, operate on an object, or maybe it’s nil, or maybe it’s some other incompatible object. Whatever, it’s all good, probably.

For Swift to work with loosey-goosey Objective-C, it has to “take its word for it” at the interface. If a parameter is supposed to be non-optional, Swift can only trust that it isn’t nil or uninitialized .

Once on the Swift side, the penalties for unexpected data are fatal. Nothing is allowed to be unexpected. Whereas Objective-C will send nil s to nil and possibly just put itself into a weird state, Swift will crash.

Depending on your crash and exception logging tool, the crash log may be pretty unhelpful. But if you’re lucky, you’ll get something like this:

Exception: SIGTRAP
Location: YourSwiftFile.swift line 25

SIGTRAP?

A SIGTRAP exception here is more-often-than-not Swift’s less articungte way of saying “Swift unexpectedly found nil.”

Consider some utility code written in Swift:

//SwiftUtility.swift
 
func printObject(_ object: SomeObject) {
    print(object)
}

and some Objective-C code consuming it:

//SomeObjectiveCFile.m
 
SomeObject *object = nil;
[SwiftUtilityprintObject: object];

The Objective-C compiler will have no problem with the code. Since we’re not explicitly handing nil over to Swift, the _Nonnull requirement will not raise any warning flags.

On the Swift side, print() expects Any . It will happily inspect and report about an optional value that happens to be nil , but crashes with EXC_BAD_ACCESS here.

The Bottom Line

This may seem trivial and/or obvious, but a SIGTRAP can pop up in tricky ways in legacy projects. If you’re used to the optional value safety of Swift, you may forget to consider the possibility that your nice non-optional variables have been sabotaged. If an asynchronous operation is involved, you may not even see any Objective-C files in the stack trace.

Share Your Findings

What are your experiences with Objective-C + Swift legacy apps? Have you encountered any cryptic problems with simple solutions? Let us know in the comments below.


用户评论
开源开发学习小组列表