我正在从远程源实现下载请求,我遇到了@escaping函数的概念。正如Apple所说:
当闭包被传递时,闭包被称为转义函数 函数的参数,但在函数返回后调用。
但我实际上注意到(使用断点工具)它在return语句之前调用和实现。
static func fetchFeaturedApps(completionHandler: @escaping ([AppCategory]) -> ()) {
let urlString = "https://api.letsbuildthatapp.com/appstore/featured"
URLSession.shared.dataTask(with: URL(string: urlString)!) {
(data, response,error) -> Void in
if error != nil {
print(error?.localizedDescription)
return
}
do {
let json = try(JSONSerialization.jsonObject(with: data!, options: .mutableContainers)) as! Dictionary<String, Any>
var appCategories = [AppCategory]()
// invokes before return [![enter image description here][1]][1]
completionHandler(appCategories)
for dict in json["categories"] as! [[String: Any]] {
let appCategory = AppCategory()
appCategory.setValuesForKeys(dict)
appCategories.append(appCategory)
}
print(appCategories)
DispatchQueue.main.async {
// completionHandler(appCategories)
}
} catch let error as NSError {
print(error.localizedDescription)
}
}.resume()
}
然后是
,当然在它处理&#34; completionHandler&#34;它继续实现函数,就好像我发送它的简单闭包。
在return语句之前发现@escaping闭包调用,严格地说是在函数体中调用它的地方。
但我想也许我错了?也许苹果牢记另一种情况?请问我如何理解@escaping符号与Apples引用关于在返回后调用它们?实际上在它回来之前调用的例子中,为什么?
答案 0 :(得分:4)
你说:
在我在函数体中调用它的地方严格地说
@escaping
闭包[被称为]。
是的,这恰恰发生了什么。无论您将其放在代码中的哪个位置,都可以调用它。如果您在从方法返回之前碰巧打电话给它,那就是它将会做什么。
正如其他人所指出的那样,它被声明为@escaping
这一事实意味着可以稍后调用,而不是必然会被调用后面。
实际上,这种同步调用@escaping
闭包的模式(即在方法返回之前)并不罕见。例如,如果您正在处理可以缓存响应的网络请求,则会看到此情况。在这种情况下,如果资源已被检索,您可以检查缓存并立即调用闭包,但如果之前没有缓存,则异步调用闭包,现在必须从Web异步检索资源。例如,你可能有类似的东西:
func fetchImage(for identifier: String, completion: @escaping (UIImage?) -> Void) {
if let image = cache.retrieveImage(for: identifier) {
completion(image)
return
}
webService.fetchImageAsynchronously(for: identifier) { image in
completion(image)
}
}
注意,仅仅因为闭包被指定为@escaping
,这并不意味着我的代码路径需要异步调用它,无论如何。我可以同步或异步地调用闭包,无论什么都有意义。
有人说过,如果你有一个方法,你知道你将总是同步调用闭包,你就不会使用@escaping
指定。不仅在非转义场景中无偿使用@escaping
会使代码不清楚,但@escaping
指定会阻止编译器执行某些类型的优化。所以我们只使用@escaping
所需的地方,即在那些我们知道它将会或可以异步调用的情况下。
答案 1 :(得分:2)
正如文件中所述:
当闭包作为参数传递给函数时,闭包被称为转义函数,但在函数返回后调用。当声明一个以闭包作为其参数之一的函数时,可以在参数的类型之前编写@escaping,以指示允许闭包转义。
在函数返回后,声明闭包@escaping
不会使其执行。它只是意味着函数返回后可能或可能不会执行,这完全取决于您的代码。
关于你的代码,你的闭包是在函数上下文中直接调用的,所以难怪在函数返回之前执行闭包。如果您希望在函数返回后执行它,您可能需要使用某些多线程机制,如GCD
或OperationQueue
。