user6808779
user6808779

Reputation:

try-catch inside closure -> Invalid conversion from throwing to non-throwing function type

I have marked my function with throws, why does swift force me to use a do-try-catch block?

I want to handle any kind of error thrown where I call this function below.

static func getPosts() throws {

    let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")
    let request = URLRequest(url: url!)

    let session = URLSession.shared
    session.dataTask(with: request) { (data, response, error) in

        let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableLeaves) as! [String: Any]  

    }.resume()        
}

Below is screen-shot of error I am getting.

Upvotes: 0

Views: 571

Answers (2)

vadian
vadian

Reputation: 285082

It's impossible to catch an error from within a closure.

A suitable solution is an enum and a completion handler

enum PostResult {
    case success([String:Any]), failure(Error)
}

func getPosts(completion:@escaping (PostResult)->() ) {

    let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!
    // no URLRequest needed !
    let session = URLSession.shared
    session.dataTask(with: url) { (data, response, error) in
        if let error = error { 
            completion(.failure(error)) 
            return
        }
        do {
            let json = try JSONSerialization.jsonObject(with: data!) as! [String: Any]
            completion(.success(json))
        } catch {
            completion(.failure(error))
        }

    }.resume()
}

And use it

getPosts { result in
    switch result {
    case .success(let json): print(json)
         // process json 
    case .failure(let error): print(error)
         // handle error
    }
}

Upvotes: 0

Fangming
Fangming

Reputation: 25261

Your throws is saying that your getPosts() function itself will throw. However, it finished before the closure is called, which means that even if the json parsing throws exception, you have passed the time that the exception can be caught and handled.

Errors within a closure has to be handled in the closure. You are looking for something like

static func getPosts(completion: @escaping (_ error: String) -> Void) {

    let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")
    let request = URLRequest(url: url!)

    let session = URLSession.shared
    session.dataTask(with: request) { (data, response, error) in
        do {
            let json = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableLeaves) as! [String: Any]
            completion("ok")
        }catch let error {
            print(error)
            completion("error")
        }

    }.resume()        
}

Upvotes: 0

Related Questions