Escaping闭包是指"逃离"调用函数作用域的闭包(例如,为异步执行保存)。
在Swift中,函数默认接受non-escaping闭包:闭包在函数调用范围内执行。
为了明确指定escaping使用关键字@escaping:
func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
关键区别:
[weak self]或[unowned self]以防止内存泄漏(retain cycle)。在传递给调用DispatchQueue.async的函数参数的闭包时,是否总是需要写@escaping?
— 是的。因为DispatchQueue.async会在执行前保存闭包,闭包将变为escaping。
示例:
func foo(action: () -> Void) { DispatchQueue.main.async { action() // 编译不通过:闭包必须是escaping。 } } // 应该: func bar(action: @escaping () -> Void) { ... }
故事
控制器在escaping闭包内对self创建了强引用(例如网络请求)。控制器在离开屏幕后未被释放——强retain cycle。解决方案:使用[weak self]或[unowned self]。
故事
函数将闭包传递给DispatchQueue.async,但未将其标记为escaping。项目未能编译,错误由于函数嵌套而难以找到。
故事
在闭包内访问了一个在闭包调用时已经被析构的对象(使用了[unowned self])。结果——运行时崩溃。解决方案:使用[weak self]并进行nil检查。