1 闭包的本质其实是一个引用类型:存储在堆空间上,由堆分配空间,且生命周期由ARC(自动引用计数机制)管理
2 捕获值:闭包会捕获上下文使用到的变量(引用类型会保持引用关系),如果没有显式捕获列表, swift会默认按值捕获局部变量或对引用类型捕获强引用。为了避免强引用循环,可以通过[weak self]或[unowned self]来避免。如下所示
class Counter {
var total = 0
func makeIncrementer() -> () -> Int {
return { [unowned self] in
self.total += 1
return self.total
}
}
}
let counter = Counter()
let incrementer = counter.makeIncrementer()
print(incrementer()) // 输出: 1
print(incrementer()) // 输出: 2
print(counter.total) // 输出: 2
3 延迟执行
闭包中的代码只有在闭包被调用时才会执行,适合回调和异步任务。
let greeting: () -> Void = {
print("Hello, Swift!")
}
print("Before calling the closure")
greeting() // 闭包被调用,这里的代码才会执行
print("After calling the closure")
输出
Before calling the closure
Hello, Swift!
After calling the closure
闭包延迟执行在事件处理中的应用,举例:比如我要给网络发送一条请求,得到数据来更新我的UI视图,但是网络的响应时间我们是不确定的,所以就会导致更新UI的时机并不确定。我们就可以借助逃逸闭包@escaping来解决这个问题,@escaping 用于标记闭包参数,表示这个闭包可能会在函数返回后被异步调用。闭包会在函数作用域之外执行,而不是在函数调用时立即执行,然后在闭包中执行更新逻辑。如下面的例子,我们在闭包中更新answer就可以解决该问题了。
Swift
func chatRequest(inputId : String,input : String,completion:@escaping(String) -> Void) {
//completion会异步自动调用
completion(String)
}
if let question = questions{
request?.chatRequest(inputId:inputID,input: question){[weak self] answer in
self?.answer = answer
}
}