2016-12-24 56 views
-2
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。

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

回答

3

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

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

感谢您的全面回答@vacawwama。我有几个问题。如果我比较“//传递闭包”和“//与尾部闭包语法”何时使用闭包以及何时使用尾部闭包?任何特定情况?为什么这是用于关键字?输入参数?为什么这个$ 0用于?如果在用于描述输入参数那么在问题的行“{(数据,响应,错误) - > Void in”中怎么样。 – user804417

+1

@ user804417,如果最后一个参数采用闭包,则通常使用尾随闭包语法。 'in'关键字将参数从闭包体中分离出来。 '$ 0'代表第一个参数。如果你有3个参数,那么你会使用'$ 0','$ 1'和'$ 2'。 – vacawama

+0

非常感谢主席先生!现在很清楚! – user804417

1

当您调用该函数时,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 
} 
+0

感谢Nirav的回答。当该块被调用时,我可以理解,但块的主体在哪里? (虽然我不太确定闭包是否和块一样工作) – user804417

+1

@ user804417当你调用fetchAllRooms函数时,在你完成(房间)的术语体中是“{rooms in}”。 –

+0

知道了Nirav,非常感谢。我还有一个问题, – user804417

1

Objective-C的块和斯威夫特闭包是同样的事情,用不同的名称和语法略有不同,但它们是可以互换的。

在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()函数调用传递给它的完成处理程序函数。 (这里有两层完成处理程序。)这是在Objective-C和Swift中使用aysnc库的一种非常常见的模式。

Swift与Objective-C一样有一个“尾随闭包”语法。在这两种语言中,如果函数的最后一个参数是块/闭包,可以将块闭合拉到括号外,跳过参数标签,并简单地使用大括号提供块/闭包。在Objective-C中,您必须在块的前面加上可怕的^以使编译器很高兴,但否则两者非常相似。