Xcode 7ベータ版をインストールしてSwiftコードをSwift 2に変換した後、私は理解できないコードに関する問題をいくつか抱えていました。私はSwift 2が新しいことを知っているのでそれについて何もないので私は検索して把握します、私は質問を書くべきです。
これがエラーです:
呼び出しはスローすることができますが、 'try'とマークされておらず、エラーは処理されません
コード:
func deleteAccountDetail(){
let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
let request = NSFetchRequest()
request.entity = entityDescription
//The Line Below is where i expect the error
let fetchedEntities = self.Context!.executeFetchRequest(request) as! [AccountDetail]
for entity in fetchedEntities {
self.Context!.deleteObject(entity)
}
do {
try self.Context!.save()
} catch _ {
}
}
スナップショット:
save()
呼び出しに対して既に行っているのと同じようにエラーを捕捉する必要があります。また、ここで複数のエラーを処理しているので、次のように単一のdo-catchブロックで複数のtry
呼び出しを順次実行できます。
func deleteAccountDetail() {
let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
let request = NSFetchRequest()
request.entity = entityDescription
do {
let fetchedEntities = try self.Context!.executeFetchRequest(request) as! [AccountDetail]
for entity in fetchedEntities {
self.Context!.deleteObject(entity)
}
try self.Context!.save()
} catch {
print(error)
}
}
あるいは、@ bames53が以下のコメントで指摘しているように、エラーがスローされた場所でキャッチしないことをお勧めします。メソッドをthrows
、次にtry
とマークしてメソッドを呼び出すことができます。例えば:
func deleteAccountDetail() throws {
let entityDescription = NSEntityDescription.entityForName("AccountDetail", inManagedObjectContext: Context!)
let request = NSFetchRequest()
request.entity = entityDescription
let fetchedEntities = try Context.executeFetchRequest(request) as! [AccountDetail]
for entity in fetchedEntities {
self.Context!.deleteObject(entity)
}
try self.Context!.save()
}
Swiftでthrows
で宣言されている関数を呼び出すときは、関数呼び出しサイトにtry
またはtry!
で注釈を付ける必要があります。例えば、投げ関数が与えられると:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
この関数は次のように呼び出すことができます。
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
ここでは、呼び出しにtry
という注釈を付けています。これは、この関数が例外をスローする可能性があることを読者に呼びかけ、それ以降のコード行は実行されない可能性があります。この関数は例外をスローする可能性があるため(つまり、willOnlyThrowIfTrue()
がスローされると、throws
は自動的に例外を上方にスローします)、この関数にfoo
というアノテーションも付ける必要があります。
おそらくスローするように宣言されているが正しい入力を与えているのであなたがあなたのケースにスローしないことを知っている関数を呼び出したい場合は、try!
を使用できます。
func bar() {
try! willOnlyThrowIfTrue(false)
}
こうすれば、コードがスローされないことを保証するときに、例外の伝播を無効にするために余分な定型コードを追加する必要はありません。
try!
は実行時に強制されます。もしtry!
を使用していて、その関数が投げてしまうと、プログラムの実行は実行時エラーで終了します。
ほとんどの例外処理コードは上記のようになります。例外が発生したときに単に例外を上方に伝播するか、そうでなければ可能性のある例外が除外されるように条件を設定します。コード内の他のリソースのクリーンアップは、オブジェクトの破棄(つまりdeinit()
)、または場合によってはdefer
edコードを介して行う必要があります。
func baz(value: Bool) throws {
var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
var data = NSData(contentsOfFile:filePath)
try willOnlyThrowIfTrue(value)
// data and filePath automatically cleaned up, even when an exception occurs.
}
何らかの理由で実行する必要があるがdeinit()
関数に含まれていないコードをクリーンアップする場合は、defer
を使用できます。
func qux(value: Bool) throws {
defer {
print("this code runs when the function exits, even when it exits by an exception")
}
try willOnlyThrowIfTrue(value)
}
例外を扱うほとんどのコードは単にそれらをdeinit()
またはdefer
を経由してクリーンアップすることで、呼び出し元に上向きに伝播させるだけです。これは、ほとんどのコードでエラーの対処方法がわからないためです。何が悪かったのかはわかっていますが、エラーについて何をすべきかを知るために、より高いレベルのコードが何をしようとしているのかについて十分な情報がありません。ユーザーにダイアログを表示することが適切かどうか、それを再試行する必要があるかどうか、または何か他のものが適切かどうかはわかりません。
ただし、より高レベルのコードでは、エラーが発生した場合の対処方法を正確に知っておく必要があります。そのため、例外によって、特定のエラーが最初に発生した場所から処理できる場所にまで拡大することができます。
例外処理はcatch
ステートメントによって行われます。
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
それぞれが異なる種類の例外をキャッチする複数のcatchステートメントを持つことができます。
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
例外を含むベストプラクティスの詳細については、 http://exceptionsafecode.com/ を参照してください。これは特にC++を対象としていますが、Swiftの例外モデルを検討した結果、基本はSwiftにも当てはまると思います。
Swiftの構文とエラー処理モデルの詳細については、ブック 『Swiftプログラミング言語(Swift 2 Prerelease)』 を参照してください。