【问题标题】:Please help me to understand this code snippet [closed]请帮助我理解这个代码片段[关闭]
【发布时间】:2016-12-24 14:11:06
【问题描述】:
public func fetchAllRooms(completion: ([RemoteRoom]?) -> Void) {
  let url = NSURL(string: "http://localhost:5984/rooms/_all_docs?include_docs=true")!

  let urlRequest = NSMutableURLRequest(
    URL: url,
    cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
    timeoutInterval: 10.0 * 1000)
  urlRequest.HTTPMethod = "GET"
  urlRequest.addValue("application/json", forHTTPHeaderField: "Accept")

  let task = urlSession.dataTaskWithRequest(urlRequest)
    { (data, response, error) -> Void in
    guard error == nil else {
      print("Error while fetching remote rooms: \(error)")
      completion(nil)
      return
    }

    guard let json = try? NSJSONSerialization.JSONObjectWithData(data!,
      options: []) as? [String: AnyObject] else {
        print("Nil data received from fetchAllRooms service")
        completion(nil)
        return
    }

    guard let rows = json["rows"] as? [[String: AnyObject]] {
      print("Malformed data received from fetchAllRooms service")
      completion(nil)
      return
    }

    var rooms = [RemoteRoom]()
    for roomDict in rows {
      rooms.append(RemoteRoom(jsonData: roomDict))
    }

    completion(rooms)
  }

  task.resume()
}

我是 Swift 的新手。

fetchAllRooms 函数接受另一个名称完成的函数,该函数接受一个参数数组 RemoteRoom 并返回 void。

现在,完成块(语法看起来像 Objective c 中的块回调)正在使用参数 RemoteRoom 调用。 RemoteRoom 被初始化,完成块被称为completion(rooms)。但是完成块的主体在哪里?当行:completion(rooms) 被执行时要执行的行是什么。

【问题讨论】:

    标签: ios swift callback completionhandler


    【解决方案1】:

    完成块的主体是传递的函数或闭包的主体。以下示例都做同样的事情:

    func fetch(completion: (Int) -> Int) {
        print("executing fetch")
    
        let result = completion(5)
        print("completion(5) returns \(result)")
    }
    
    // calling it passing a function with the right signature
    func addOne(i: Int) -> Int {
        return i + 1
    }
    
    fetch(completion: addOne)
    
    // passing a closure
    fetch(completion: { i in return i + 1 })
    
    // same with trailing closure syntax
    fetch() { i in
        return i + 1
    }
    
    // () isn't needed if completion is the only parameter
    fetch { i in
        return i + 1
    }
    
    // simplified closure removing parameter name and return
    fetch { $0 + 1 }
    

    【讨论】:

    • 感谢@vacawwama 非常全面的回答。我有几个问题。如果我比较“//传递闭包”和“//与尾随闭包语法相同”何时使用闭包以及何时使用尾随闭包?有什么具体案例吗?为什么 this in 关键字用于?输入参数?为什么要使用这个 0 美元?如果 in 用于描述输入参数,那么在问题行“{ (data, response, error) -> Void in”中呢?
    • @user804417,如果最后一个参数采用闭包,您通常使用尾随闭包语法。 in 关键字将参数与闭包体分开。 $0 代表第一个参数。如果您有 3 个参数,那么您将使用 $0$1$2
    • 非常感谢先生!现在很清楚了!
    • let task = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) -> Void in guard error == nil else { print("获取远程房间时出错:(error)") completion(nil) return } 下面的块可以替代上面的块吗? let task = urlSession.dataTaskWithRequest(urlRequest) { (data, response, error) -> 如果 let myerror = error! { print("获取远程房间时出错:(myerror)") completion(nil) return }
    【解决方案2】:

    completion 的块部分在您调用该函数时被调用(执行)。 completion(rooms) 的调用将执行您调用此函数fetchAllRooms 的完成块。

    self.fetchAllRooms() { rooms in
        //When you call completion(rooms) this block will be executed and you get [RemoteRoom] 
        in rooms instance
    
        //do something with rooms instance here
    } 
    

    【讨论】:

    • 感谢 Nirav 的回答。当调用块时我可以理解,但是块的主体在哪里? (虽然我不太确定闭包是否与块的工作方式相同)
    • @user804417 在您调用 fetchAllRooms 函数时,completion(rooms) 的术语主体为 { rooms in }
    • 知道了 Nirav,非常感谢。我还有一个问题,
    • @user804417 它是什么?
    • { (data, response, error) -> Void in , this in 关键字是干什么用的?
    【解决方案3】:

    Objective-C 块和 Swift 闭包是同一个东西,名称不同,语法略有不同,但它们是可以互换的。

    在Objective-C中,系统有一个UIView动画类方法animateWithDuration:animations:。想象一下它的实现:

    @interface UIView
    
    +(void) animateWithDuration: (int) duration, animations: (void (^)(void)) animations {
       //set up animation
       animations();
       //finish animations
    }
    

    动画块的主体在哪里?

    它是由调用者提供的。 animations() 行调用传入方法的块。

    fetch() 函数也是如此。它需要一个名为completion 的块/闭包。 fetch 函数使用异步 URLSession(Objective-C 中的 NSURLSession)dataTask 来下载数据,并为数据任务提供完成处理程序。

    一旦数据任务完成,数据任务的完成处理程序代码就会运行。在该完成处理程序中,fetch() 函数调用传递给它的完成处理程序函数。 (这里有 2 个级别的完成处理程序。)这是在 Objective-C 和 Swift 中使用 aysnc 库的一种非常常见的模式。

    Swift 有一个“尾随闭包”语法,就像 Objective-C 一样。在这两种语言中,如果函数的最后一个参数是块/闭包,您可以将块闭包拉到括号之外,跳过参数标签,并简单地为块/闭包提供大括号。在 Objective-C 中,您必须在代码块前面加上可怕的 ^ 才能使编译器满意,但除此之外,两者非常相似。

    【讨论】:

      猜你喜欢
      • 2013-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      • 2015-12-09
      • 1970-01-01
      • 2010-11-12
      相关资源
      最近更新 更多