Swift 2で、URLからデータを取得し、NSURLSessionを使用してJSONオブジェクトとして返す関数を作成したいと思います。最初は、これは非常に簡単に思えました。次のように書きました。
_func getJson(url:NSURL, completeWith: (AnyObject?,NSURLResponse?,NSError?)->Void) -> NSURLSessionTask? {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url) {
(data:NSData?, response:NSURLResponse?, error:NSError?) -> Void in
if error != nil {
completeWith(nil, response, error)
}
if let data = data {
do {
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
} catch let caught as NSError {
completeWith(nil, response, caught)
}
completeWith(object, response, nil)
} else {
completeWith(nil, response, error)
}
}
return task
}
_
ただし、完了ブロックが「スロー」を宣言していないため、コンパイルされません。正確なエラーはCannot invoke 'dataTaskWithURL' with an argument list of type '(NSURL, (NSData?, NSURLResponse?, NSError?) throws -> Void)'
です。 _do/catch
_ステートメントですべてのエラーをキャッチしていますが、SwiftはNSErrorをチェーンの上位に伝播したいと考えています。それを回避する唯一の方法は、_try!
_、このように:
_if let data = data {
let object:AnyObject? = try! NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
completeWith(object, response, nil)
} else {
completeWith(nil, response, error)
}
_
これですべてが正常にコンパイルされますが、_NSJSONSerialization.JSONObjectWithData
_によってスローされるNSErrorが失われました。
_NSJSONSerialization.JSONObjectWithData
_によってスローされる可能性のあるNSErrorをキャプチャし、完了ブロックの署名を変更せずに完了ブロックに伝播できることはありますか?
私はあなたのキャッチが網羅的ではないと思うので、あなたはこのようなものが必要です:
do
{
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
completeWith(object, response, nil)
} catch let caught as NSError {
completeWith(nil, response, caught)
} catch {
// Something else happened.
// Insert your domain, code, etc. when constructing the error.
let error: NSError = NSError(domain: "<Your domain>", code: 1, userInfo: nil)
completeWith(nil, nil, error)
}
jguffeyからの質問に対処するため。次のような関数を呼び出そうとすると、同じエラーが発生しました。
let taskResult = getJson(url!) {
(any: AnyObject,resp: NSURLResponse,error: NSError) in
次のようになります。
let taskResult = getJson(url!) {
(any: AnyObject?,resp: NSURLResponse?,error: NSError?) in
NSJSONSerializationは、NSErrorではなくErrorTypeをスローします。
したがって、正しいコードは次のようになります
do {
let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
} catch let caught as ErrorType {
completeWith(nil, response, caught)
}
また、メソッドのシグネチャをErrorTypeに変更します。
このため、受け入れられた回答は常に「何か他のことが起こった」ブロックに入り、NSJSONSerialization.JSONObjectWithDataによってスローされたエラーを報告することはありません。