是的,如果您的线程阻塞正常工作,这就是它的工作原理(即,在您完成所有异步操作后断点命中该行)。
这里,completionHandler 是一种在 Swift 中称为闭包的值类型。它的行为有点像 lambdas/匿名函数/等。 (“种类”是指它如何与 Swift 的垃圾收集 ARC 配合使用,ARC 与其他流行语言的工作方式不同。不过,这是一个单独的话题。)。
这些闭包本质上是函数指针,所以你基本上是在注入一个函数作为可以在你的函数中使用的参数。
换句话说,这就像给你的函数一个带有按钮的盒子。只要它可以提供必要的输入,您的函数就可以随时按下该按钮。在这种情况下,需要URLResponse? 才能按下该按钮。当按下该按钮时,此函数的调用者将执行其定义的任何代码块(同步或将来某个时间)。
因为您的问题涉及“幕后”
我建议阅读一些 Swift [文档][1]。如果有不明白的地方,请继续在这里评论。其他人花了几个小时用我无法在此处合理模仿的大量细节和行为来完善该页面。
专业提示:不要忘记使用[weak self]!!!
评论回复:
非常感谢,但我还有一个问题:你说“如果你的线程阻塞工作正常”,但在一般情况下,会发生吗?我的意思是,如果我对阻塞线程、添加断点什么都不做,……会发生吗? - phuongzzz
我们来看这个例子:
//You can copy-paste the following into a playground
import Foundation
//MARK:- FUNCTIONS
//Here's a buggy function
func intentionallyBuggyFunction(onDone: @escaping (String) -> ())
{
var resultTxt = "Oops the async did not happen"
DispatchQueue.main.asyncAfter(deadline: .now() + 3)
{
resultTxt = "The async happened!"
}
onDone(resultTxt)
}
//Here's one that'll async properly (this example is just for demonstration purposes)
func thisOneWillWork(onDone: @escaping (String) -> ())
{
let thread = DispatchQueue(label: "Bambot", qos: .userInteractive, attributes: .concurrent,
autoreleaseFrequency: .workItem, target: nil)
thread.async {[onDone]
var resultTxt = "Oops the async did not happen"
let dg = DispatchGroup()
dg.enter()
thread.asyncAfter(deadline: .now() + 3)
{[weak dg] in
resultTxt = "The async happened!"
dg?.leave()
}
dg.wait()
onDone(resultTxt)
}
}
//MARK:- CODE EXECUTION
//This'll print the wrong result
intentionallyBuggyFunction { (resultStr) in
print(resultStr)
}
//This'll print the right result
thisOneWillWork { (resultStr) in
print(resultStr)
}
如您所见,第一个函数将异步内容排队,立即执行闭包,然后点击其结束函数大括号。即使闭包正在转义,该函数也会在异步内容发生之前完成执行。
第二个函数实际上指示设备在单独的线程上等待挂起的更新。这样,String 在闭包被调用之前就被更新了。
现在,我认为第二个功能是意大利面条式代码。像这样随意启动 DispatchQueue 并不是一个好习惯,因为 iOS 的池中只有这么多线程可供选择。它也滥用了 DispatchGroup(对于这样的行为,你应该创建一个串行队列(你可以谷歌那个)。
最好只捕获完成处理程序{[onDone](...) in,然后在实际的异步块中调用它,如下所示:
//Better async (cleaner, makes more sense, easier to read, etc.)
func betterAsync(onDone: @escaping (String) -> ())
{
var resultTxt = "Oops the async did not happen"
DispatchQueue.main.asyncAfter(deadline: .now() + 3)
{[onDone] in
resultTxt = "The async happened!"
onDone(resultTxt)
}
}