swift - Swift 为嵌套回调保护弱自我
问题描述
我的问题更像是答案的更好练习。假设我们有多个嵌套的回调层,我们必须使每一层都self
成为weak
并且我知道我们可以guard
为每一层编写(参见代码片段 1),但这甚至有必要吗?如果我们只守在第一层就足够了吗(见代码片段2)?
如果我们从引用计数的角度思考,第一个strongself
是否足够好?
片段1:
let callBack1 = { [weak self] xx in
guard let strongSelf = self { return }
// strongSelf.func(param)
let callBack2 = { [weak self] yy in {
guard let strongSelf = self { return }
// strongSelf.func(param)
let callBack3 = { [weak self] zz in
guard let strongSelf = self { return }
// strongSelf.func(param)
}
}
}
片段 2:
let callBack1 = { [weak self] xx in
guard let strongSelf = self { return }
// strongSelf.func(param)
let callBack2 = { [weak self] yy in {
// strongSelf.func(param)
let callBack3 = { [weak self] zz in
// strongSelf.func(param)
}
}
}
注意:这是我们代码库中的一个合法案例,不要假设这永远不会发生。
编辑:为了澄清这个问题,我们假设每个回调都是异步发生的,self
这里是引用当前类(可能是模型,可能是视图控制器),可以在三个回调中的任何一个发生期间释放/弹出。
解决方案
我认为@Andriy 的大部分回答都是正确的。但最正确的答案是我们甚至不需要放入[weak self]
任何嵌套块。
当我第一次从同事那里听到这个时,我不想买它。但事实是,第一个块定义了被捕获的自我 ,这个被捕获的自我将影响当前范围内所有被捕获的自我,换句话说,在第一个块的. 因此,如果我们在第一层回调中已经完成了,就不需要再申请了。self
weak
{}
[weak self]
很难从 Apple 那里找到确切的文档来证明这一点,但以下带有核心基础保留计数的代码片段CFGetRetainCount()
可以证明这是真的。
class TestClass {
var name = ""
var block1: (()->Void)?
var block2: (()->Void)?
func test() {
print(CFGetRetainCount(self))
self.block1 = { [weak self] in
self?.block2 = { // [weak self] in
print(CFGetRetainCount(self))
}
self?.block2?()
print(CFGetRetainCount(self))
}
self.block1?()
print(CFGetRetainCount(self))
}
deinit {
print(CFGetRetainCount(self))
}
}
do {
let tstClass = TestClass()
print(CFGetRetainCount(tstClass))
tstClass.test()
print(CFGetRetainCount(tstClass))
}
如果您有兴趣,可以在您的 Playground 中尝试一下,随时删除对[weak self]
for block2 的评论,您将看到相同的答案。
保留计数始终为 2 并且deinit
被正确调用。
推荐阅读
- html - 我可以将整个 HTML 文档放在模板中吗?
- php - 带有 PHP 参数的 Python 脚本
- scala - Scala:从 Elasticsearch 获取超过 10000 个文档/消息
- reporting-services - 来自先前数据集的 SSRS 临时表停止工作
- python - 使用 list.count 使用 .sort() 对列表进行就地排序不起作用。为什么?
- javascript - 获取响应 blob 作为边缘中的对象 HTML 元素数据
- multiprocessing - 为什么不同核数的多处理代码的运行时间相同?
- java - 在模块 classes.jar 中发现重复的类
- android - 没有firebase可以使用GCP吗?
- reactjs - IIS 8.5 rewrite rule subdirectory and ReactJs