11

我想在 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.

有没有我可以捕获可能抛出的 NSErrorNSJSONSerialization.JSONObjectWithData并将其传播到完成块而不修改完成块的签名?

4

3 回答 3

21

我认为,你的收获并不详尽,所以你需要这样的东西:

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)
}
于 2015-06-15T09:09:55.937 回答
2

解决Jguffey的问题。当我尝试调用这样的函数时,我看到了同样的错误:

let taskResult = getJson(url!) { 
     (any: AnyObject,resp: NSURLResponse,error: NSError) in

它应该是这样的:

let taskResult = getJson(url!) { 
         (any: AnyObject?,resp: NSURLResponse?,error: NSError?) in
于 2015-08-10T03:53:23.993 回答
1

NSJSONSerialization 抛出 ErrorType 而不是 NSError。

所以正确的代码是

do {
    let object:AnyObject? = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
} catch let caught as ErrorType {
    completeWith(nil, response, caught)
}

您还将方法签名更改为 ErrorType。

出于这个原因,接受的答案将始终进入“发生了其他事情”块,并且永远不会报告 NSJSONSerialization.JSONObjectWithData 抛出的错误。

于 2015-11-09T21:52:37.653 回答