开端
Objective-C 中,有一段重复写到你不得不加入 snippets
的代码块。就是下面这段
1 | __weak __typeof__(self) weakSelf = self; |
一般,由于重复写的次数过多,就加到了 snippets
快捷代码块,以下是我的:
当然,如果用了 RAC,你可以写成如下代码:
1 | @weakify(self); |
当然,如果你阅读过 RAC 对 @weakify
和 @strongify
语法糖的实现,你会知道,实现方式不过是用宏简写了 __weak __typeof__(self) weakSelf = self;
和 __strong __typeof(weakSelf)strongSelf = weakSelf;
重点是为什么要写这两句代码?
weakSelf 是为了避免循环引用(如果你对循环引用和内存管理不了解的话,请调跳到下方 Other 部分)。
strongSelf 是为了防止 self 被提前释放。具体可以参考 深入研究Block用weakSelf、strongSelf、@weakify、@strongify解决循环引用。
你以为 Swift 中不需要 strongSelf 了吗?
Swift 中有了 [weak self]
语法糖后,再也不用谢一长串 __weak __typeof__(self) weakSelf = self;
,相应的,在闭包中会调用到已经被弱引用的 self
,但使用 self
时需要加上 ?
。
这里就已经可以初见端倪了,和 Objective-C 一样,weak 引用的 self
是可以被释放的,也就是说 self
可以为 nil
。在 Objective-C 中,没有可选性概念,所以对此并不感知,在 Swift 中问题就很容易暴露出来。如果 self
被提前释放了会如何?
我们做如下代码:
1 | class ViewController: UIViewController { |
这段代码运行结果如下:
这就是问题所在了。代码中可以清晰的看到,在闭包中代码运行的过程中,anObject
被设置成了 nil
,此时没有任何对象强引用它,自然被释放了,释放后闭包中代码继续运行,self
此时为 nil
,但由于 Swfit 的安全性,self?.log("after sleep")
没有解包成功便不会执行,所以不会造成闪退。但问题依然有。
由于后续代码没有执行,造成的其他逻辑错误是可想而知的,如果闭包中正在执行存磁盘操作,self
被释放,后续还有更新 UI 显示等等操作,便不会执行,造成各种各样的问题。
所以,你以为 Swift 中就不需要 strongSelf
了?不,以后你的代码仍然需要:
1 | DispatchQueue.global(qos: .userInitiated).async { [weak self] in |
当然,你可以加到 snippets
,这样就可以快速插入代码了:
总结
Swift 和 Objective-C 大不同,但是 iOS 内存管理仍然是 iOS 内存管理,ARC 仍然是 ARC,所以不管语法怎么变,关于内存和引用依旧还是原来的样子,strongSelf
也好,循环引用也好,千万别忘了去注意。
代码
代码都在这里
Other
如果以下这幅图中的三个问题,你不能清晰的答出答案和其理由,建议你去读一读 Objective-C 关于内存管理的源码哟。这里是我的两篇博文,希望能帮到你:
以下是三个问题:
有什么问题都可以在博文后面留言,或者微博上私信我。
博主是 iOS 妹子一枚。
希望大家一起进步。
我的微博:Lotty周小鱼