一同养成写作习惯!这是我参加「日新方案 4 月更文挑战」的第20天,点击查看活动概况。
- 本文首要介绍RxSwift中的内存办理,以及循环引证状况,和如何防止循环引证
1. 循环引证
一般咱们闭包会捕获持有者的话会形成循环引证,打破循环引证一般咱们会运用弱引证打破循环
,比方运用[weak self]
,无主引证[unowned self]
,这儿有的时分比方会出现逃逸闭包
的状况,比方咱们闭包的使命在之后进行。
此时就会产生溃散,此时self
被释放了,2秒后咱们调用闭包。此时咱们能够运用【weak self】
润饰,就有了空安全
判读,可是咱们self
释放了,无法打印特点名字。这个时分还是要运用强引证
,
咱们运用局部变量strongSelf
持有咱们的self
,在异步函数闭包作用域内
,内部履行完成后就释放了strongSelf
。
咱们能够运用guard
护卫形式优雅一些
var myClousre:(()->())?
self.myClousre = { [weak self] in
print(self?.name as Any)
guard let strongSelf = self else {
return
}
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now()+2) {
strongSelf.name = "jackLove"
print(strongSelf.name as Any)
}
}
self.myClousre!()
2.RxSwift中的内存办理
RxSwift
中大量的闭包的调用,因而防止不了导致一些循环引证
导致无法释放。那么如何防止内存走漏呢?RxSwift
对咱们的观察者
和序列
设计了一套自己的引证计数。
比方咱们的序列
public class Observable<Element> : ObservableType {
init() {
#if TRACE_RESOURCES
_ = Resources.incrementTotal()
#endif
}
public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
rxAbstractMethod()
}
public func asObservable() -> Observable<Element> { self }
deinit {
#if TRACE_RESOURCES
_ = Resources.decrementTotal()
#endif
}
}
在init
和deinit
中对引证计数的增减,相同关于匿名观察者
final class AnonymousObserver<Element>: ObserverBase<Element> {
typealias EventHandler = (Event<Element>) -> Void
private let eventHandler : EventHandler
init(_ eventHandler: @escaping EventHandler) {
#if TRACE_RESOURCES
_ = Resources.incrementTotal()
#endif
self.eventHandler = eventHandler
}
override func onCore(_ event: Event<Element>) {
self.eventHandler(event)
}
#if TRACE_RESOURCES
deinit {
_ = Resources.decrementTotal()
}
#endif
}
因而咱们能够经过打印RxSwift.Resources.total
表示当时的RxSwift
中资源
运用状况。当然咱们也能够运用当时页面的deinit
打印是否释放
,只是经过RxSwift.Resources.total
咱们能够快速定位
到咱们关于RxSwift
形成的内存走漏
状况。
在podfile中导入下面代码
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == 'RxSwift'
target.build_configurations.each do |config|
if config.name == 'Debug'
config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['-D', 'TRACE_RESOURCES']
end
end
end
end
end
2.1 持有序列crate闭包捕获
关于咱们序列持有者在crate
的闭包中持有self
,会形成循环引证
其持有链:
self->ob->crate闭包->self
相同的咱们能够运用弱引证打破循环
2.2 持有序列subscribe闭包捕获
关于在持有的序列的订阅闭包
中捕获self
。相同形成了循环引证
其持有链:
由于 self->ob序列->subscribe闭包->self
相同的咱们能够运用弱引证打破循环
2.3 持有观察者在crate闭包捕获
咱们持有observer
,一般咱们会赋值全局变量,这样咱们能够自动调用on事情
,比方咱们在点击屏幕发送12
Observable<Int>.create { ober in
self.observer = ober
return Disposables.create()
}.subscribe(onNext: {[unowned self] in
print(self.name as Any)
print($0)})
.disposed(by: disposeBag)
能够发现没有形成循环引证
self--\-> ob-->crate闭包->self
咱们没有持有序列所以没有形成循环引证
2.4 持有观察者在subscribe闭包捕获
咱们在订阅中捕获self
能够发现形成了循环引证
分析下 self-->observer-->eventHandle(订阅闭包)-->self
3.传递中的序列
咱们一般会有一些作为参数传递的状况,相似咱们oc中的block
,咱们能够在概况页
fileprivate var mySubject = PublishSubject<Any>()
var publicOB : Observable<Any>{
return mySubject.asObservable()
}
这样的优点,咱们经过转化隐藏内部的具体完成,内部运用mySubject
进行调用,外部则暴漏publicOB
。
咱们push的时分给publicOB
进行赋值
咱们点击的时分跳转概况页面,返回的时分能够发现页面毁掉
了,没什么问题,可是咱们能够发现咱们Rx资源数量
不断增加,说明咱们的序列没有被释放
。咱们能够发现publicOB
是主页的垃圾袋进行毁掉办理的。因而咱们能够
3.1 处理序列毁掉方式
- 不相关
disposeBag
由于咱们当时的页面 的垃圾袋disposeBag
没有移除,因而不会dispose()
咱们不相关当时的页面的垃圾袋则能够完毕相关
。
- 相关地点页面的
disposeBag
咱们的序列和当时的概况页是同一个生命周期
,因而能够运用vc的disposeBag
-
take(until:)
咱们运用take(until:)
添加序列的判断条件:当页面毁掉
的时分完毕序列。
- 自动调用
相同的咱们在页面要离开的时分自动发送complete
事情从而自动调用dispose()
3.2 循环引证处理
咱们如果对vc进行特点持有不重复创建,重复操作,发现咱们的订阅没有呼应
这儿咱们能够发现咱们的订阅闭包捕获了self,因而形成了循环引证
self->detailVC->pulishOB->eventHandle->self
关于无法呼应咱们能够看下PublishSubject发送OnComplete
事情后
因而咱们能够发现咱们之前离开页面的时分发送completd
事情后,下次再发送就无法呼应了。
- 处理
咱们初始化的时分从头初始化PublishSubject
,在订阅闭包免除捕获强引证。
4. 总结
在RxSwift中咱们运用的时分注意是否形成循环引证
,咱们能够配合RxSwift.Resources.total
运用打印页面的运用状况。关于闭包的捕获能够看下我之前的文章Swift闭包的多个值捕获