从抛出函数类型(_, _, _) throws -> Void到非抛出函数类型(NSData?, NSURLResponse?, NSError?) -> Void的转换无效。

68

我已经写好了这段代码:

func getjson() {
        let urlPath = "https://api.whitehouse.gov/v1/petitions.json?limit=100"
        let url = NSURL(string: urlPath)
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
            print("Task completed")
            if(error != nil) {
                print(error!.localizedDescription)
            }
            let err: NSError?
            if let jsonResult = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary {
                if(err != nil) {
                    print("JSON Error \(err!.localizedDescription)")
                }
                if let results: NSArray = jsonResult["results"] as? NSArray {
                    dispatch_async(dispatch_get_main_queue(), {
                        self.tableData = results
                        self.Indextableview.reloadData()
                    })
                }
            }
        })

        task.resume()

    }

更新到XCode 7后,我遇到了这个错误:从抛出函数类型(_, _, _)throws - > Void 到非抛出函数类型(NSData?, NSURLResponse?, NSError?)-> Void 的无效转换。这在let task这一行出现。

谢谢。


请指出导致问题的代码行,并使用完整和准确的错误信息更新您的问题。 - rmaddy
但是我应该在哪里使用try?@LeoDabus - Martin Mikusovic
在 try 后面加上代码,如果成功运行,则执行。 - Leo Dabus
我已更新完整的错误信息@rmaddy - Martin Mikusovic
尝试的代码被用在非try-catch块中。这种情况发生在我身上。通过将try xxx更改为try? xxx来修复它。 - slboat
4个回答

75

您需要按照以下方式实现Do Try Catch错误处理:

import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

extension URL {
    func asyncDownload(completion: @escaping (_ data: Data?, _ response: URLResponse?, _ error: Error?) -> ()) {
        URLSession.shared
            .dataTask(with: self, completionHandler: completion)
            .resume()
    }
}

let jsonURL = URL(string: "https://api.whitehouse.gov/v1/petitions.json?limit=100")!
let start = Date()
jsonURL.asyncDownload { data, response, error in

    print("Download ended:", Date().description(with: .current))
    print("Elapsed Time:", Date().timeIntervalSince(start), terminator: " seconds\n")
    print("Data size:", data?.count ?? "nil", terminator: " bytes\n\n")

    guard let data = data else {
        print("URLSession dataTask error:", error ?? "nil")
        return
    }

    do {
        let jsonObject = try JSONSerialization.jsonObject(with: data)
        if let dictionary = jsonObject as? [String: Any],
            let results = dictionary["results"] as? [[String: Any]] {
            DispatchQueue.main.async {
                results.forEach { print($0["body"] ?? "", terminator: "\n\n") }
      //        self.tableData = results
      //        self.Indextableview.reloadData()
            }
        }
    } catch {
        print("JSONSerialization error:", error)
    }
}
print("\nDownload started:", start.description(with: .current))

2
有没有办法将错误传递到更高层?因为我的“getjson”函数在一个单独的类中。我不想打印错误描述,而是要在UIAlertController中向用户显示它。但是UIAlertController只能从调用“getjson”函数的UIViewController中显示。 - Adarkas2302
1
由于@Adarkas2302是一个异步方法,最简单的方法是发布一个通知,并将观察者添加到需要显示警报的视图控制器上。https://dev59.com/910a5IYBdhLWcg3wRGrp#30541063 - Leo Dabus
@HariHonor 我的代码里没有开关。 - Leo Dabus

21

正如Leo建议的那样,你的问题在于你使用了try,但没有在do-try-catch结构中使用它,这意味着它推断出闭包被定义为抛出错误,但由于它没有被定义为这样,所以你会得到那个错误。

因此,请添加do-try-catch

func getjson() {
    let urlPath = "https://api.whitehouse.gov/v1/petitions.json?limit=100"
    let url = URL(string: urlPath)!
    let session = URLSession.shared
    let task = session.dataTask(with: url) { data, response, error in
        print("Task completed")

        guard let data = data, error == nil else {
            print(error?.localizedDescription)
            return
        }

        do {
            if let jsonResult = try JSONSerialization.jsonObject(with: data) as? [String: Any] {
                if let results = jsonResult["results"] as? [Any] {
                    DispatchQueue.main.async {
                        self.tableData = results
                        self.indexTableView.reloadData()
                    }
                }
            }
        } catch let parseError {
            print("JSON Error \(parseError.localizedDescription)")
        }
    }

    task.resume()
}

1
在Swift 2中,将所有NSError替换为ErrorType
试一下。
  class func fetchWeatherForLocation(locationCode: String = "", shouldShowHUD: Bool = false, completionHandler: (data: NSDictionary?, error: ErrorType?) -> ()) {



    let url = NSURL(string: "myurl")               
    let task =  NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in

        if let dataWithKey = data {

            do {
                let jsonForDataWithTemprature = try NSJSONSerialization.JSONObjectWithData(dataWithKey, options:NSJSONReadingOptions.MutableContainers)

                guard let arrayForDataWithKey :NSArray = jsonForDataWithTemprature as? NSArray else {
                    print("Not a Dictionary")
                    return
                }

                let dictionaryWithTemprature = arrayForDataWithKey.firstObject as! NSDictionary

                completionHandler(data: dictionaryWithTemprature, error: nil)

            }
            catch let JSONError as ErrorType {
                print("\(JSONError)")
            }

        }
    }

    task.resume()
}

0

在代码的try-catch中更改错误类型对我有用。

“将所有NSError替换为ErrorType”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接