内存管理是开发中不可忽视的问题,而循环引用又是引起内存泄漏的最常见的问题。 让我们来看几个简单的问题,以及如何解决:
循环引用
var name:String?
var myClosure : (() -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
myClosure = {
self.name = "马小撂"
}
myClosure!()
}
然后我们用析构函数检查是否循环引用
deinit {
print("deinit")
}
上面的函数调用,当离开页面的时候,没有走deinit
方法,self
持有了myClosure
,myClosure
有持有了self
,明显产生了循环引用。
那我们该如何打破这种持有的方法呢?
方法一:使用无主引用unowned
myClosure = {[unowned self] in
self.name = "马小撂"
}
myClosure!()
方法二:使用弱引用weak
myClosure = {[weak self] in
self?.name = "马小撂"
}
myClosure!()
那么无主引用unowned
和弱引用weak
有什么区别呢?接下来让我们在里面加个延时再来看看。
myClosure = {[unowned self] in
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.name = "马小撂"
print(self.name ?? "")
}
}
myClosure!()
会报错Attempted to read an unowned reference but the object was already deallocated
,对象已经被释放了
那我们看看用weak
修饰的呢?
myClosure = {[weak self] in
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self?.name = "马小撂"
print(self?.name as Any)
}
}
myClosure!()
结果打印nil
,这是为什么呢?是因为unowned
无主引用是将两者同时销毁,而weak
将在self
销毁时置为nil
。
那我们该如何解决这个问题呢?延长self
的生命周期,和OC中的weakSelf
和strongSelf
是一样的。
延长生命周期(guard)
myClosure = {[weak self] in
guard let self = self else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
self.name = "马小撂"
print(self.name!)
}
}
myClosure!()
因为
self
已经被移除关键字,所以用self
和strongSelf
是一样的。
RXSwift 中的循环引用
既然闭包这么容易引起循环引用,而在RXSwift
中创建序列,订阅都会使用大量的闭包,什么情况会引起循环引用呢?
情况一:
self.pwdTF.rx.text.orEmpty.skip(1)
.bind(to: self.rx.title)
.disposed(by: disposeBag)
self.pwdTF.text
绑定self.rx.title
并没有引起循环引用,因为self.rx.title
作为一个参数,不会引起循环引用。
情况二:
self.observable = Observable<Any>.create({ (anyObserver) -> Disposable in
anyObserver.onNext("马小撂")
print(self)
return Disposables.create()
})
创建序列闭包中使用self, self -> observable -> create{} -> self 构成了循环引用
self.observable?.subscribe(onNext: { (argue) in
print(self)
}).disposed(by: disposeBag)
订阅闭包中使用self,self -> observable -> subscribe{} -> self 构成了循环引用。
情况三:
Observable<Any>.create { (anyObserver) -> Disposable in
self.observer = anyObserver
anyObserver.onNext("马小撂")
print(self)//临时变量,没有产生循环引用
return Disposables.create()
}.subscribe(onNext: { (item) in
print(item)
print(self)//循环引用
}).disposed(by: disposeBag)
}
创建序列闭包
anyObserver
是一个临时变量,赋值给self
,不会产生循环引用,而订阅闭包中:self -> bag -> sink -> AnonymousObserver -> _eventHandler,所以在订阅中使用self,就要注意了。
解决方法: 在RXSwift中打破循环引用,不仅仅是使用weak 还有很多其他的办法
解决方法:
例如合理使用.completed或.error
手动调dispose()
使用.takeUntil(deallocated)