【问题标题】:how to represent nil Error Swift completion block如何表示 nil Error Swift 完成块
【发布时间】:2018-03-28 21:27:34
【问题描述】:

您好,我在 swift 中有一个 Web 服务工作者对象,它将完成块传递给调用者视图控制器。代码如下:

func getFlightData(for airportCode: String, minutesBehind:String, minutesAhead:String, completion: (([Flight], NSError) -> Void)?) {
    var urlComponents = URLComponents()
    urlComponents.scheme = "https"
    urlComponents.host = "xxxxxxx.com"
    urlComponents.path = "/1/airports/"+airportCode+"/flights/flightInfo"
    urlComponents.queryItems = [
        URLQueryItem(name: "city", value: airportCode),
        URLQueryItem(name: "minutesBehind", value: minutesBehind),
        URLQueryItem(name: "minutesAhead", value: minutesAhead)

    ]

    guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.setValue("xxxxxxxxx", forHTTPHeaderField: "Authorization")
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)


    let task = session.dataTask(with: request) { (responseData, response, responseError) in
        DispatchQueue.main.async {


            if let error = responseError {

                //completion block???


            }

            else if let jsonData = responseData {

                let decoder = JSONDecoder()

                do {
                    let posts = try decoder.decode([Flight].self, from: jsonData)
                    //completion?(posts, nil) ???? what to pass for Error? Successful call
                } catch {
                    self.showError()

                }
            }

            else {
                //completion block???
                self.showError()
            }
        }
    }
    task.resume()
}

调用成功时,我在完成块错误参数中传递了什么值。我不能通过 nil,因为 swift 不允许我这样做。有人可以建议一种更好的方法来进行此 API 调用吗?如何发送完成块等。

【问题讨论】:

    标签: ios swift xcode completion-block


    【解决方案1】:

    它不接受nil,因为您的参数NSError 不是可选的。

    声明你的方法签名喜欢

    func getFlightData(for airportCode: String, minutesBehind:String, minutesAhead:String, completion: (([Flight], NSError?) -> Void)?) {
    
    ....
    
    }
    

    它应该可以工作

    【讨论】:

    • 不要使用NSErrorError 协议更灵活,更符合 Swift 的习惯。
    • 这不是问题,我不知道他的其余实现。如果他使用NSError 可能有一些原因
    • NSError 符合Error,因此任何采用Error 的东西都可以接受NSError。没有理由在 Swift API 中使用 NSError
    • 假设......是的......仍然不知道,只是回答他的问题
    【解决方案2】:

    将完成块声明为采用Error? 而不是NSError,然后您将能够在成功的情况下将nil 传递给它。 ? 是使参数可选的原因,这使得它可以包含 nil。 (另外,使用 Error 而不是 NSError,因为它是惯用的 Swift 错误类型)。

    或者,您可以让您的完成块采用 Result 枚举,您可以这样定义:

    public enum Result<T> {
        case success(T)
        case error(Error)
    
        public func unwrap() throws -> T {
            switch self {
            case let .success(ret):
                return ret
            case let .error(error):
                throw error
            }
        }
    }
    

    然后您可以使用.success.error 情况,具体取决于操作是成功还是失败。

    【讨论】:

    • 完成!我的响应数据呢?我该如何发送?万一出现错误?
    • @Ackman Result 类型用于响应数据和错误相互排斥的情况。如果您可能想在出现错误时读取响应数据,请坚持使用元组实现,但使用 Error? 而不是 NSError
    • 我已经做到了,你能在我的代码中告诉我如何进行这些更改吗?我仍然很困惑。我应该保留错误吗?或将 Result 保留在我的完成块中。我对 swift 还很陌生,很难理解这一点
    • 如果您希望能够同时传递响应数据错误,那么就按照您所做的那样做,但是将NSError 替换为Error?。您可以完全按照您所做的那样使用它,除了现在您可以传递nil 而不会出现编译器错误。如果收到错误意味着响应数据不相关(常见情况),则使用Result 枚举代替传递响应错误。
    • 在你的回答中你说“(另外,使用 NSError 而不是 Error,因为它是惯用的 Swift 错误类型)。”您不是说“(另外,使用Error 而不是NSError,因为它是惯用的Swift 错误类型)”吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多