SwiftでNSExceptionを処理する
Feb 20, 2016 · iosswift3objc
ObjectiveCで書かれたNSException
を発生させるソースをSwiftから利用したい時の処理方法。
NSException
は、ObjectiveCの@try ~ @catch ~ @finally
でしか例外処理を行えない。例外処理を書いていない時は、実行時エラーとして処理される。つまり、SwiftからNSException
を発生させるコードを呼び出して例外が起きると、問答無用でアプリが落ちてしまう・・・
対応策としては、
- 元のコードもSwiftで書き換えてしまう
- そもそも例外は起きるはずがないので
落ちていい無視する - 該当のメソッドを呼び出す部分をブリッジするラッパを作る
- なんとかしてSwiftで
NSException
の例外を処理する
といった感じになると思うが、サードパーティのライブラリとかだと1や2の方法が取れない場合がある。 3も該当のメソッドが多ければ作業量が多くなるし、ソースの見通しも悪くなる。
なので、今回は4の方法で例外を処理する方法についてメモしておく。
小ネタ
基本的な考えた方は3と同じで、ObjectiveCでしか処理できない部分だけラップしてしまえ〜となる。
まずは以下の様なブリッジ用のObjectiveCのクラスを作る。(Bridging-Header
への追加も忘れずに)
中は見ての通り、例外処理のそれぞれの中身をクロージャ(ブロック)でブリッジ用のクラスに渡している。
nonnull
やnullable
をつけているのは、Swift側から呼び出す時にOptional
になるかどうかを制御する為。finally
は不要なことも多々あるのでnil
を渡せる様にnullable
にしている。
(意図して処理がないことを明示させる為に空ブロックではなくnil
を渡せる様にしている)
使い方
Swiftから呼び出す時は以下の感じ。
ObjC_Exception.objC_try({ _ in
// NSExceptionが起きるかもしれない処理
},
objC_catch: { (NSException) in
// 例外発生時の処理
},
objC_finally: { _ in
// 後処理とか...
})
finally
が不要であれば、
ObjC_Exception.objC_try({ _ in
// NSExceptionが起きるかもしれない処理
},
objC_catch: { (NSException) in
// 例外発生時の処理
},
objC_finally: nil)
もし複数のcatch
が使いたい場合は、これを元に拡張すればOK。
nonnullやnullableのアノテーションについて
ObjectiveC側でアノテーションを指定すると、Swiftとの連携時のメソッドの型にも反映される。
ObjC | Swift | 変換前(ObjC) | 変換後(Swift) |
---|---|---|---|
未指定 | (型)! | Hoge* | Hoge! |
nonull _Nonnull |
(型) | Hoge* _Nonnull | Hoge |
nullable _Nullable |
(型)? | Hoge* _Nullable | Hoge? |
例えば、今回のメソッドをSwiftから呼び出す時は
ObjC_Exception.objC_try(objC_try: () -> Void, objC_catch: (NSException) -> Void, objC_finally: (() -> Void)?)
という形式になっていて、objC_finally
をnullable
にしたので、ちゃんと?
のついたOptional
になっているし、それ以外はnonnull
なので型がそのまま使われている。
開発環境
- Xcode 7.2
- iOS 9.2