基本上,“完成处理程序”没有什么特别之处。这只是一个函数。
如果你有一个函数:
func f() {
print("Hello, world")
}
而你没有调用它,那么会发生什么?好吧,什么都没有发生。
现在,这意味着什么?正如 rmaddy 所提到的,如果一个函数有一个完成,那么调用者当然希望调用该完成。 充其量,一个函数接受完成而调用者不关心完成是否曾经运行是不寻常的。*
想象一下这个函数被一个视图控制器调用,它在调用之前启动一个活动指示器,然后在完成时停止指示器。如果从不调用完成,则指示器永远不会停止旋转。
基本上就是这样。 如果未调用完成,则其代码不会运行。其效果完全取决于完成前后代码中发生的事情。
好的,你提到了内存......很多时候,完成处理程序将是一个匿名函数。在这种情况下, 会创建一个对象。但它与任何其他对象一样受制于相同的内存管理规则。没有泄漏只是因为它没有被调用。如果completeMe 看起来像这样:
func completeMe(_ completionHandler: (String) -> Void) {
completionHandler("Hello, world")
}
你这样称呼它:
completeMe({ self.detailLabel.text = $0 })
然后,当completeMe 返回时,为匿名函数创建的对象不会存在。如果您存储匿名函数:
func completeMe(_ completionHandler: @escaping (String) -> Void) {
self.handler = completionHandler
// Do other things
}
然后与任何其他对象发生相同的事情:匿名函数一直存在,直到该属性设置为另一个值(也假设没有其他对象引用它)支持>.
如果你传入一个命名函数,
func takeAString(_ s: String) {
print(s)
}
completeMe(takeAString)
takeAString 的生命周期已经是程序的生命周期;这里没有内存管理问题。
如果传入实例方法,内存管理与传入实例本身一样。
*通常,如果可能失败,您将 a) 进行第二次“失败”完成或 b) 完成将通过其参数发出失败信号。