Swift 可以放入 `if let` 块吗?

Swift can throw in `if let` blocks?

编写了这个简单的 getJson 包装器:

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
}

但是我收到关于我的 completionHandler:

的错误

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

相关说明,这是3层的if语句,它们可以被压平吗?

您的完成处理程序使用 try 关键字,该关键字在失败时抛出异常。这就是你得到错误的原因。如消息错误所述,完成处理程序需要一个非抛出方法。

您需要使用 :

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

除了抛出问题,你的代码还有很多问题。正如您所注意到的,许多嵌套的 if 使其难以阅读,但主要是,它 returns 您的 obj 变量在等待异步网络调用之前,因此不会产生您期望的结果。

下面是我将如何开始重写它。

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
    }
}