ちょっと怖すぎんだろうと思ったので記事にします。
なお、このバグはこちらでレポートされています。
https://bugs.swift.org/browse/SR-1055
発生している問題
サンプルコードはこちらです。https://github.com/fmtonakai/SwiftPropertyCrash7_3
Swiftで次のようなクラスを定義します。
enum MyEnum {
case Foo
}
class MyObject: NSObject {
let myEnum: MyEnum = .Foo
}
これを利用すると実行時にクラッシュします。
なお、ObjCとSwiftの混合プロジェクトで実行してますが、Swift onlyのプロジェクトでも同様にクラッシュが発生します。
回避方法
なんでもいいのでmyEnumの前にObjCからアクセスできるプロパティを設定します。もしくはプロパティの順番を変えて最初にObjCからアクセスできるものを一番最初に持ってきます。(どういうことなの・・・)
class MyObject: NSObject {
let str = "str"
let myEnum: MyEnum = .Foo
}
対策
自分のアプリがクラッシュするかを調べる
実行時エラーであり、問題のあるクラスを生成した時にクラッシュするので、アプリのどこでクラッシュが起こるかわかりません。アプリの中に爆弾を抱えた状態になります。
ここで、アプリがこれによってクラッシュするかを検出する方法があります。
それはObjC runtime関数のobjc_copyClassListを呼ぶことです。
このように問題のあるクラスがあるとobjc_copyClassListでBAD_ACCESS起こすので、この問題を引き起こすクラスがあることを検出できます。クラッシュしなければとりあえず安心です。(がこれから作るクラスには十分注意してください)
クラッシュを引き起こすクラスを探す
クラッシュした場合、問題のあるクラスを探す必要があります。その時、この方法が便利です。
環境変数にOBJC_PRINT_CLASS_SETUP: YES
を設定します
すると起動時にObjCのクラスのセットアップがトレースされますが、問題のあるクラスがあった場合、そこでトレースが止まります。
クラッシュ時のログ
objc[24395]: CLASS: realizing class 'PropertyCrash.MyObject' 0x1002b0ec8 0x1002aff18
objc[24395]: CLASS: realizing class 'PropertyCrash.MyObject' (meta) 0x1002c5a88 0x1002afe88
objc[24395]: CLASS: methodizing class 'PropertyCrash.MyObject' (meta)
正常時のログ
objc[24453]: CLASS: realizing class 'PropertyCrash.MyObject' 0x1002b0f30 0x1002aff80
objc[24453]: CLASS: realizing class 'PropertyCrash.MyObject' (meta) 0x1002c5af8 0x1002afe88
objc[24453]: CLASS: methodizing class 'PropertyCrash.MyObject' (meta)
objc[24453]: CLASS: methodizing class 'PropertyCrash.MyObject'
methoding classが2度行われないクラスが問題のあるクラスとわかります。
まとめ
早くHotfix出てくれー!つらい・・・