【问题标题】:What's a good example of an escape closure in Swift?什么是 Swift 中逃逸闭包的好例子?
【发布时间】:2016-03-27 07:35:47
【问题描述】:

我正在阅读 Swift 编程语言手册,其中提到了转义闭包。关于转义闭包,我不知道“闭包作为参数传递给函数,但在函数返回后被调用”是什么意思。有人可以提供一个关于转义闭包的例子吗?

【问题讨论】:

    标签: swift escaping closures


    【解决方案1】:

    转义闭包的一个示例是某些异步任务中的完成处理程序,例如发起网络请求:

    func performRequest(parameters: [String: String], completionHandler: @escaping (Result<Data, Error>) -> Void) {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try! JSONEncoder().encode(parameters)
    
        let task = URLSession.shared.dataTask(with: request) { data, _, error in
            guard let data = data else {
                completionHandler(.failure(error!))
                return
            }
            completionHandler(.success(data))
        }
        task.resume()
    }
    

    这是这样称呼的:

    performRequest(parameters: ["foo" : "bar"]) { result in
        switch result {
        case .failure(let error):
            print(error)
    
        case .success(let data):
            // now use data here
        }
    }
    
    // Note: The `completionHandler` above runs asynchronously, so we
    // get here before the closure is called, so don't try to do anything
    // here with `data` or `error`. Any processing of those two variables
    // must be put _inside_ the closure above.
    

    这个completionHandler 闭包被定义为@escaping,因为URLSession 方法dataTask 是异步运行的(即它立即返回,并且稍后会在请求完成时调用它自己的闭包)。

    【讨论】:

      【解决方案2】:

      在 Swift 3 中,闭包参数默认是不可转义的。

      我们需要在参数类型前写@escaping闭包属性,表示函数返回后调用闭包。

      typealias MyOperation = (Data?) -> ()
      
      func addToQueue(data: Data?, operation: @escaping MyOperation) {
          OperationQueue.main.addOperation {
              operation(data)
          }
      }
      

      如果我们删除@escaping属性,Xcode会在下面显示错误信息

      【讨论】:

      • 很明确的答案,有助于了解我的问题在哪里。我有 3-4 个级别的闭包,所以很难理解 @escaping 应该放在哪里。
      • 好答案。一个非常小的观察:我可能不建议Operationtypealias 名称,现有基础类的名称。这似乎是一种混淆的邀请(尤其是在这个例子中,你实际上使用的是OperationQueue)。
      猜你喜欢
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 2017-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-10
      • 2021-06-29
      相关资源
      最近更新 更多