【发布时间】:2020-07-03 07:33:20
【问题描述】:
我一直在阅读内存管理一段时间,我知道当闭包保持自我和自我保持闭包我们应该把[弱自我]打破循环,我的问题是闭包什么时候保持自我,什么时候保持自我保留一个闭包?
【问题讨论】:
标签: ios swift memory-management
我一直在阅读内存管理一段时间,我知道当闭包保持自我和自我保持闭包我们应该把[弱自我]打破循环,我的问题是闭包什么时候保持自我,什么时候保持自我保留一个闭包?
【问题讨论】:
标签: ios swift memory-management
通常很明显,但并非总是如此。
如果提及thing 或thing 的任何属性,闭包将保留thing。
如果thing 的属性是或包含函数并且该函数就是闭包,则它会保留闭包。
我在书中使用的人工示例是:
class FunctionHolder {
var function : (() -> ())?
}
func testFunctionHolder() {
let fh = FunctionHolder()
fh.function = {
print(fh)
}
}
这里,thing 是fh,一个 FunctionHolder 实例。我们将提及fh 的闭包分配给fh 的function 属性。这是一个保留周期。
现实生活中的问题是,这种情况会在您没有意识到的情况下发生。你知道你正在保留 something,但你可能没有意识到某事是或包含一个闭包。经典的例子是当你打电话时
let ob = NotificationCenter.default.addObserver(forName:...
该调用返回一个观察者对象,您保留该对象以便收到通知。但是你也提交了一个调用闭包,如果它提到了你,你就有了一个保留循环,因为你保留了包含提到你的闭包的观察者。
还有许多其他常见的此类陷阱情况。
【讨论】:
这是一个例子:
class ViewController: UIViewController {
var data = Data() {
didSet {
// do something
}
}
override func viewDidLoad() {
super.viewDidLoad()
Service.loadData { data in
self.data = data
}
perform(#selector(tryToDismiss), with: self, afterDelay: 0.5)
}
@objc func tryToDismiss() {
dismiss(animated: true)
}
deinit {
print("ViewController got deinit")
}
}
class Service {
static func loadData(completion: @escaping (Data) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
completion(Data())
}
}
}
您可以看到,即使视图控制器在加载 0.5 秒后被解除,它也没有被取消初始化,因为在 1 秒后完成加载数据的关闭。
【讨论】: