在 Swift 中,咱们能够运用 @escaping
关键字来界说逃逸闭包。逃逸闭包是指闭包在函数返回后才被调用的闭包。这种闭包一般作为异步API的回调参数,用于在异步操作完成后履行一些代码。
逃逸闭包与非逃逸闭包
闭包作为函数的参数能够是被传递和运用的。当一个闭包被界说为函数的参数时,它默以为非逃逸闭包,即它有必要在函数履行完毕前调用。可是,当一个闭包在函数返回后依然被调用时,咱们称之为逃逸闭包
运用场景
异步API的回调参数
例如,在运用URLSession
进行网络恳求时,咱们能够运用逃逸闭包来处理异步恳求的结果:
func loadData(completionHandler: @escaping (Data?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
completionHandler(data, error)
}
task.resume()
}
推迟履行的操作
例如,咱们能够运用逃逸闭包来完成一些推迟履行的操作,例如在一些情况下咱们需求在弹出视图控制器之后履行一些操作:
class MyClass {
// 默以为逃逸闭包
var completionHandler: (() -> Void)?
func doSomething() {
// 异步操作
completionHandler?()
}
}
let myObject = MyClass()
myObject.completionHandler = {
print("操作完成")
}
myObject.doSomething()
在这个比如中,咱们将界说一个completionHandler
闭包,该闭包将在视图控制器被弹出后履行。咱们能够运用逃逸闭包来完成这个功能。
当一个闭包被界说为函数的参数时,默以为非逃逸闭包
当一个闭包被界说为某个类的变量时,默以为逃逸闭包
定时器
有时候,咱们需求开启一个定时器,然后在定时器完毕后履行某些操作。运用逃逸闭包能够方便地完成这样的需求。例如:
class TimerManager {
func startTimer(duration: TimeInterval, completionHandler: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
completionHandler()
}
}
}
let timerManager = TimerManager()
timerManager.startTimer(duration: 2) {
print("定时器完毕!")
}
在这个比如中,咱们界说了一个TimerManager
类,并在其间声明晰一个逃逸闭包completionHandler
。
当咱们调用startTimer
办法时,它会开启一个计时器并在指定的时间后调用completionHandler
动画
当咱们需求在一段时间内履行一些动画操作时,能够运用逃逸闭包完成。例如:
class AnimationManager {
func animate(duration: TimeInterval, completionHandler: @escaping () -> Void) {
UIView.animate(withDuration: duration) {
// 履行动画
} completion: { finished in
completionHandler()
}
}
}
let animationManager = AnimationManager()
animationManager.animate(duration: 1) {
print("动画完毕!")
}
在这个比如中,咱们界说了一个AnimationManager
类,并在其间声明晰一个逃逸闭包completionHandler
。当咱们调用animate
办法时,它会履行一些动画操作,并在动画完成后调用completionHandler
进行处理。
运用陷阱
防止循环引证
当逃逸闭包捕获了self
或其它目标时,或许会产生循环引证的问题。假如不处理这个问题,会导致内存泄漏和应用程序的崩溃。为了防止循环引证,咱们需求运用一个弱引证或无主引证来捕获self。例如:
class MyClass {
var completionHandler: (() -> Void)?
func doSomething() {
someAsyncOperation { [weak self] in
self?.completionHandler?()
}
}
}
在这个比如中,咱们运用了一个弱引证self,防止了循环引证问题。当逃逸闭包被调用时,咱们运用self?.completionHandler?()
来访问completionHandler
属性,由于此刻self
或许现已被释放了
总结
在Swift
中,@escaping
关键字用于界说逃逸闭包,逃逸闭包一般作为异步API的回调参数运用。运用逃逸闭包有许多优点
- 异步API的回调参数有必要是逃逸闭包。由于异步API履行时间较长,非逃逸闭包或许会在函数返回之前就被销毁。因此,逃逸闭包能够确保在异步操作完成后一定会履行
- 在某些情况下,闭包需求在函数外部被调用。例如,假如咱们要将一个闭包作为一个数组的元素,那么闭包有必要是逃逸闭包
- 逃逸闭包能够使代码更加简洁和易于办理。当一个函数需求异步履行时,咱们不需求创建一个新的类或目标来办理异步操作的结果,而是能够运用逃逸闭包来处理它们