[解決済み] Swift言語でのエラーハンドリング
質問
Swiftについてあまり詳しく読んでいないのですが、ひとつ気づいたのは、例外がないということです。 では、Swiftでエラー処理をどのように行っているのでしょうか?誰かエラー処理に関連するものを見つけたことがありますか?
どのように解決するのですか?
Swift 2 & 3
Swift 2では、新しいエラー処理のメカニズムがあり、例外に多少似ていますが、細部は異なっています。
1. エラーの可能性を示す
関数/メソッドがエラーを投げる可能性があることを示したい場合、その関数/メソッドに以下の内容を含める必要があります。
throws
キーワードは次のようになります。
func summonDefaultDragon() throws -> Dragon
注意:この関数が実際に投げることのできるエラーの種類は指定されていません。この宣言は、関数が ErrorType を実装した任意の型のインスタンスを投げることができる、あるいは全く投げないということを単に述べているに過ぎません。
2. エラーを投げる可能性のある関数の起動
関数を呼び出すには、次のように try キーワードを使用する必要があります。
try summonDefaultDragon()
この行は通常、次のようなdo-catchブロックに存在する必要があります。
do {
let dragon = try summonDefaultDragon()
} catch DragonError.dragonIsMissing {
// Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
// Other specific-case error-handlng
} catch {
// Catch all error-handling
}
注:catch節はSwiftのパターンマッチのすべての強力な機能を使用するので、ここでは非常に柔軟性があります。
でマークされた関数からスローイング関数を呼び出している場合、エラーを伝播させることを決定することができます。
throws
キーワードを使用します。
func fulfill(quest: Quest) throws {
let dragon = try summonDefaultDragon()
quest.ride(dragon)
}
また、スローイング関数を呼び出すには
try?
:
let dragonOrNil = try? summonDefaultDragon()
この方法では、何らかのエラーが発生した場合、戻り値かnilを取得します。この方法では、エラーオブジェクトを取得することはできません。
ということは
try?
のような便利な文があります。
if let dragon = try? summonDefaultDragon()
または
guard let dragon = try? summonDefaultDragon() else { ... }
最後に、そのエラーが実際に発生しないことが分かっている場合(例えば、前提条件を既にチェックしている場合など)には、次のようにします。
try!
というキーワードがあります。
let dragon = try! summonDefaultDragon()
もしこの関数が実際にエラーを投げたら、アプリケーションにランタイムエラーが発生し、アプリケーションは終了してしまいます。
3. エラーのスローイング
エラーを投げるには、throw キーワードを次のように使用します。
throw DragonError.dragonIsMissing
に適合するものであれば何でも投げることができます。
ErrorType
プロトコルを使用します。まず始めに
NSError
はこのプロトコルに準拠していますが、おそらくは列挙型の
ErrorType
これにより、関連する複数のエラーをグループ化することができ、さらに次のようなデータを追加することもできます。
enum DragonError: ErrorType {
case dragonIsMissing
case notEnoughMana(requiredMana: Int)
...
}
Swift 2 & 3 の新しいエラー機構と Java/C#/C++ スタイルの例外の主な違いは以下の通りです。
-
構文が少し違います。
do-catch
+try
+defer
vs トラディショナルtry-catch-finally
の構文があります。 - 例外処理では、通常、成功パスよりも例外パスの方がはるかに高い実行時間が発生します。これは Swift 2.0 のエラーの場合ではなく、成功パスとエラーパスはほぼ同じコストです。
- 例外はどこからでも投げられる可能性がありますが、エラーを投げるコードはすべて宣言されていなければなりません。すべてのエラーは、Javaの命名法では"checked exceptions"です。しかし、Javaとは対照的に、潜在的にスローされるエラーを指定することはありません。
-
Swiftの例外は、ObjCの例外と互換性がありません。あなたの
do-catch
ブロックはNSExceptionをキャッチしませんし、その逆も同様です。 -
Swiftの例外はCocoaと互換性がある
NSError
のどちらかを返すというメソッド規則があります。false
(の場合Bool
を返す関数)またはnil
(の場合AnyObject
を返す関数)、およびNSErrorPointer
をエラーの詳細と一緒に表示します。
エラー処理を容易にするための構文上の補助として、さらに2つの概念があります。
-
ディファレンシャルアクション
defer
キーワード) で、Java/C#/etc の finally ブロックと同じ効果を得ることができます。 -
ガード文
guard
キーワード)を使うことで、通常のエラーチェックやシグナリングのコードよりもif/elseのコードを少なく書くことができます。
スウィフト1
ランタイムエラーです。
Leandrosが提案するように、実行時エラー(ネットワーク接続の問題、データの解析、ファイルのオープンなど)の処理には、次のようにします。
NSError
ObjCでやったように、Foundation、AppKit、UIKitなどがこの方法でエラーを報告するからです。というのも、Foundation、AppKit、UIKitなどはこの方法でエラーを報告するからです。つまり、言語というよりフレームワークの問題です。
また、AFNetworkingのようなセパレータの成功/失敗のブロックも頻繁に使われるパターンです。
var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
success: { (NSURLSessionDataTask) -> Void in
println("Success")
},
failure:{ (NSURLSessionDataTask, NSError) -> Void in
println("Failure")
})
それでも頻繁に受信される障害ブロック
NSError
インスタンスで、エラーを記述しています。
プログラマーのエラー。
プログラマエラー(配列要素の境界外アクセス、関数呼び出しに渡された無効な引数など)については、ObjCで例外を使用していましたね。Swift言語では、例外の言語サポートはないようです(例えば
throw
,
catch
などのキーワード)。しかし、ドキュメントにあるように、これはObjCと同じランタイムで実行されているため、ObjCと同じように
NSExceptions
このように
NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()
ObjCコードで例外をキャッチすることを選ぶかもしれませんが、純粋なSwiftでそれらをキャッチすることはできません。
問題は、プログラマーのエラーに対して例外を投げるべきか、それともAppleが言語ガイドで提案しているようにアサーションを使うべきかということです。
関連
-
[解決済み】「Fatal error: Unexpectedly found nil while unwrapping an Optional value "とはどういう意味ですか?
-
[解決済み] Swift言語におけるエクスクラメーションマークの意味とは?
-
[解決済み] Swiftで乱数を生成する方法とは?
-
[解決済み] SwiftからObjective-Cのコードを呼び出すにはどうしたらいいですか?
-
[解決済み] Swift Betaのパフォーマンス:配列のソート
-
[解決済み] Swiftでdispatch_onceのシングルトンモデルを使う
-
[解決済み] 2倍値を小数点以下x桁に丸める処理を素早く行う。
-
[解決済み] SwiftでStringのサブストリングはどのように動作するか
-
[解決済み】swiftでDoubleを最も近いIntに丸めるには?
-
[解決済み】なぜ、Swiftの文字列では、?のような絵文字が奇妙に扱われるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] テスト
-
[解決済み] メインスレッドチェッカー バックグラウンドスレッドで呼び出された UI API: -[UIApplication applicationState].
-
[解決済み] Swift Optionals - 条件の変数バインディングはイニシャライザを必要とする
-
[解決済み] このコンテキストで型検索を行う場合、「メソッド」は曖昧である、Alamofireのエラー
-
[解決済み] Swiftで文字列が別の文字列を含んでいるかどうかを確認するには?
-
スレッド1:シグナルSIGABRTの問題解決
-
[解決済み】Swift 4でStringのsubstringを使うには?'substring(to:)'は非推奨です。部分的な範囲から'演算子を持つ文字列スライス添字を使用してください。
-
[解決済み】Swiftでオブジェクトが与えられた型かどうかを確認する
-
[解決済み】swiftで変数のメモリアドレスを印刷する
-
[解決済み】ReactiveCocoaとRxSwiftの比較 - 長所と短所?