Releaseビルドでのみクラッシュするアプリへ行った対策について

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは!
モバイルアプリサービス部の田中孝明です。

今回はXcode 8.1 + Swift 2.3の環境でReleaseビルドをかけるとアプリがDebug時には起きなかった場所でクラッシュするようになった問題にあたった時、急遽対策を行った内容を共有したいと思います。

経緯

Xcode 7.3 + Swift 2.1で作成されていたあるプロジェクトをiOS 10に対応するためにXcode 8.1とSwift 2.3に対応させていました。
Swift 3.0ではなく、Swift 2.3なのは3.0対応のライブラリがiOS 9以上が対象だったため、Deployment Target がiOS 8のプロジェクトは移行できなかった側面があります。

今回Releaseビルドを行って実機で確認したところ、Alamofireのエラーハンドリング処理でクラッシュするようになってしまいました。

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libobjc.A.dylib                 0x0000000197b37bdc objc_msgSend + 28
1   libswiftCore.dylib              0x00000001013f48a8 0x101340000 + 739496
2   libswiftCore.dylib              0x00000001013f475c 0x101340000 + 739164
3   libswiftCore.dylib              0x00000001013f73f0 0x101340000 + 750576
4   Foundation                      0x0000000188200040 -[NSError dealloc] + 68
5   MyApp                           0x00000001001441bc Foo.(hoge(completion : (NSError?) -> ()) -> ()).(closure #1) (Foo.swift:61)
6   MyApp                           0x00000001001b385c Bar.(request(completionHandler : (json : AnyObject?, date : NSDate?, error : NSError?) -> ()) -> Request).(closure #1) (Bar.swift:241)
7   MyApp                           0x00000001001bab70 partial apply for Bar.(request(completionHandler : (json : AnyObject?, date : NSDate?, error : NSError?) -> ()) -> Request).(closure #1) (Bar.swift:0)
8   Alamofire                       0x0000000100820960 partial apply for thunk (ResponseSerialization.swift:0)
9   Alamofire                       0x0000000100820498 specialized Request.(response<A where ...> (queue : OS_dispatch_queue?, responseSerializer : A, completionHandler : (Response<A.SerializedObject, A.ErrorObject>) -> ()) -> Self).(closure #1).(closure #1) (ResponseSerialization.swift:142)
10  libdispatch.dylib               0x00000001981693a8 _dispatch_call_block_and_release + 20
11  libdispatch.dylib               0x0000000198169368 _dispatch_client_callout + 12
12  libdispatch.dylib               0x000000019816d97c _dispatch_main_queue_callback_4CF + 928
13  CoreFoundation                  0x00000001873d1fa0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
14  CoreFoundation                  0x00000001873d0048 __CFRunLoopRun + 1488
15  CoreFoundation                  0x00000001872fd0a0 CFRunLoopRunSpecific + 392
16  GraphicsServices                0x00000001904a75a0 GSEventRunModal + 164
17  UIKit                           0x000000018bc323bc UIApplicationMain + 1484
18  MyApp                           0x00000001000ad570 main (AppDelegate.swift:14)
19  libdyld.dylib                   0x0000000198192a04 start + 0


NSErrordealocをコールした後にクラッシュしています。

対策

詳しい原因については追って調査中ですが、対策としてReleaseビルド時の最適化を他のビルド設定と同じにしました。

Xcodeのプロジェクトのターゲットを選択し、Build Settingsを選択します。
1

Optimizationの項目を選択し、最適化の設定を確認します。

2

Releaseの設定をNoneに変更します。

3

本対策は最適な解決手段では無いことをご了承ください。
最適化をやめることでバイナリのサイズや処理時間の改善に影響を及ぼす可能性はあります。

まとめ

一応バグレポートとして報告しましたので、後のXcodeのバージョンによっては直る可能性もあります。
また、Swift 2.3ではなく、Swift 3.0に移行した際には掲題のような問題は起きない可能性もあります。

Xcode 8.1 + Swift 2.3という限定的な環境でのアクシデントでしたが、同じようなトラブルで悩まれている方の助けになれば幸いです。