我想深入了解闭包及其分配和使用机制。在阅读并使用它们一段时间后,我想出了一些真正让我头疼的问题:
问题 - 1 从内存分配的角度来看,闭包如何用作与正常变量不同的变量?
例如:let x:NSString ={}()
& let x = NSString()
问题-2 块的内存分配究竟如何?
请妥善解释这些,以便任何有类似疑虑的读者都可能从中受益。
**编辑* Shadow提出的这个问题的答案是针对这个问题的另一个方向进行了编辑。
答案 0 :(得分:1)
对于具有默认值或默认闭包的存储属性,在调用init
方法之前,内存会分配。您不能使用self
或属性来默认值定义其他属性。
通常在此步骤中使用的示例中的闭包来定义lazy
属性;它们应为var
并标有lazy
关键字:
class myClass {
let x: NSString? = nil
let q: NSString? = {return "q"}() //allocates before class init; deallocates imidiatly
lazy var y: NSString = {
let z = self.x
return z ?? ""
}() //allocates on first property call; deallocates imidiatly
}
延迟属性的内存将在第一次属性调用时分配。构造{/*...*/}()
意味着此闭包将在调用时执行,并将返回计算结果(您可以在未命名的函数中查看它),而不是引用此闭包。这是非常重要的时刻:你没有保留闭包,这个闭包只分配执行时刻并在返回后释放,所以你不需要关心强循环引用问题。
其他事项 - 当您保存对闭包的引用时:
class myClass {
let x: NSString? = nil
var closure: () -> NSString = {return "q"} //allocates before class init; deallocates on references release
lazy var lazyClosure: () -> NSString = {
let z = self.x
return z ?? ""
} //allocates on first property call; deallocates on references release
}
此闭包的内存与之前的情况同时分配,但它们将继续存在,直到有任何引用。你可以在这里查看闭包,就像在不同的对象一样。这里可能出现循环参考问题。 closure
没有捕获任何内容,因此它没有任何问题,但lazyClosure
捕获self
。如果我们永远不会调用lazyClosure
那么就没有问题,因为这个闭包永远不会分配。但是,如果我们将其调用,它将被分配,它将捕获self
,并且将有强循环引用:self
指向lazyClosure
实例,lazyClosure
指向self
个实例。要解决此问题,您应该使其中一个引用变弱,您应该使用捕获列表:在[weak self] in
正文中插入[unowned self] in
或lazyClosure
。我们的情况为[unowned self] in
,因为如果调用了属性,则self
不是nil
。
lazy var lazyClosure: () -> NSString = {
[unowned self] in
let z = self.x
return z ?? ""
}