A T
A T

Reputation: 13846

Swift can throw in `if let` blocks?

Wrote this simple getJson wrapper:

func getJson<T>(path: String) -> T? {
    let url = URL(string: path)
    let session = URLSession.shared
    var obj: T?
    if let usableUrl = url {
        let task = session.dataTask(with: usableUrl,
          completionHandler: { (data, response, error) in        // # <-- this line
            if let data = data {
                if let stringData = String(
                      data: data, encoding: String.Encoding.utf8) {
                    let decoder = JSONDecoder()
                    obj = try decoder.decode(T.self, from: json)
                }
            }
        })
        task.resume()
    }
    return obj
}

But I get this error about my completionHandler:

Invalid conversion from throwing function of type '(_, _, _) throws -> ()' to non-throwing function type '(Data?, URLResponse?, Error?) -> Void'

On a related note, this is 3 layers of if statements, can they be flattened?

Upvotes: 0

Views: 663

Answers (2)

Gereon
Gereon

Reputation: 17882

Your code has quite a lot of problems apart from the throwing issue. Like you noticed, the many nested ifs make it hard to read, but mainly, it returns your obj variable before waiting for the asynchronous network call and thus wouldn't produce the results you're expecting.

Here's how I would start rewriting it.

func getJson<T: Decodable>(path: String, completion: @escaping (T?) -> () ) {
    guard let url = URL(string: path) else {
        return
    }

    let session = URLSession.shared
    let task = session.dataTask(with: url) { (data, response, error) in
        if let data = data {
            do {
                let obj = try JSONDecoder().decode(T.self, from: data)
                completion(obj)
            } catch {
                completion(nil)
            }
        }
    }
    task.resume()
}

// usage example:

struct Foo: Decodable {
    let bar: Int
}

getJson(path: "http://example.com") { (obj: Foo?) in
    if let foo = obj {
        // processs data
    } else {
        // an error occurred
    }
}

Upvotes: 3

Omar
Omar

Reputation: 221

Your completion handler uses a try keyword that throws an exception when it fails. That's why you get an error. Completion handler expects a non throwing method as the message error says.

You need to catch the error by using :

do {
    obj = try decoder.decode(T.self, from: json)
} catch {
    print("error") // Write here what you want to do if decoder fails.
}

Upvotes: 0

Related Questions