一同养成写作习惯!这是我参加「日新方案 4 月更文挑战」的第20天,点击查看活动概况。

  • 本文首要介绍RxSwift中的内存办理,以及循环引证状况,和如何防止循环引证

1. 循环引证

一般咱们闭包会捕获持有者的话会形成循环引证,打破循环引证一般咱们会运用弱引证打破循环,比方运用[weak self],无主引证[unowned self],这儿有的时分比方会出现逃逸闭包的状况,比方咱们闭包的使命在之后进行。

RxSwift学习-17-RxSwift中的内存管理
此时就会产生溃散,此时self被释放了,2秒后咱们调用闭包。此时咱们能够运用【weak self】润饰,就有了安全判读,可是咱们self释放了,无法打印特点名字。这个时分还是要运用强引证

咱们运用局部变量strongSelf持有咱们的self,在异步函数闭包作用域内,内部履行完成后就释放了strongSelf

RxSwift学习-17-RxSwift中的内存管理
咱们能够运用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

RxSwift学习-17-RxSwift中的内存管理

2.1 持有序列crate闭包捕获

关于咱们序列持有者在crate的闭包中持有self,会形成循环引证

RxSwift学习-17-RxSwift中的内存管理
其持有链: self->ob->crate闭包->self

相同的咱们能够运用弱引证打破循环

2.2 持有序列subscribe闭包捕获

关于在持有的序列的订阅闭包中捕获self。相同形成了循环引证

RxSwift学习-17-RxSwift中的内存管理
其持有链: 由于 self->ob序列->subscribe闭包->self 相同的咱们能够运用弱引证打破循环

2.3 持有观察者在crate闭包捕获

咱们持有observer,一般咱们会赋值全局变量,这样咱们能够自动调用on事情,比方咱们在点击屏幕发送12

RxSwift学习-17-RxSwift中的内存管理

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闭包捕获

RxSwift学习-17-RxSwift中的内存管理

咱们在订阅中捕获self

能够发现形成了循环引证

分析下 self-->observer-->eventHandle(订阅闭包)-->self

3.传递中的序列

咱们一般会有一些作为参数传递的状况,相似咱们oc中的block,咱们能够在概况页

fileprivate var mySubject = PublishSubject<Any>()
  var publicOB : Observable<Any>{
    return mySubject.asObservable()
  }

这样的优点,咱们经过转化隐藏内部的具体完成,内部运用mySubject进行调用,外部则暴漏publicOB

RxSwift学习-17-RxSwift中的内存管理

咱们push的时分给publicOB进行赋值

RxSwift学习-17-RxSwift中的内存管理

咱们点击的时分跳转概况页面,返回的时分能够发现页面毁掉了,没什么问题,可是咱们能够发现咱们Rx资源数量不断增加,说明咱们的序列没有被释放。咱们能够发现publicOB是主页的垃圾袋进行毁掉办理的。因而咱们能够

3.1 处理序列毁掉方式

  • 不相关disposeBag

RxSwift学习-17-RxSwift中的内存管理

由于咱们当时的页面 的垃圾袋disposeBag没有移除,因而不会dispose()咱们不相关当时的页面的垃圾袋则能够完毕相关

  • 相关地点页面的disposeBag

RxSwift学习-17-RxSwift中的内存管理

咱们的序列和当时的概况页是同一个生命周期,因而能够运用vc的disposeBag

  • take(until:) 咱们运用take(until:)添加序列的判断条件:当页面毁掉的时分完毕序列。

RxSwift学习-17-RxSwift中的内存管理

  • 自动调用

相同的咱们在页面要离开的时分自动发送complete事情从而自动调用dispose()

RxSwift学习-17-RxSwift中的内存管理

3.2 循环引证处理

咱们如果对vc进行特点持有不重复创建,重复操作,发现咱们的订阅没有呼应

RxSwift学习-17-RxSwift中的内存管理

这儿咱们能够发现咱们的订阅闭包捕获了self,因而形成了循环引证 self->detailVC->pulishOB->eventHandle->self 关于无法呼应咱们能够看下PublishSubject发送OnComplete事情后

RxSwift学习-17-RxSwift中的内存管理
因而咱们能够发现咱们之前离开页面的时分发送completd事情后,下次再发送就无法呼应了。

  • 处理

RxSwift学习-17-RxSwift中的内存管理

咱们初始化的时分从头初始化PublishSubject,在订阅闭包免除捕获强引证。

4. 总结

在RxSwift中咱们运用的时分注意是否形成循环引证,咱们能够配合RxSwift.Resources.total运用打印页面的运用状况。关于闭包的捕获能够看下我之前的文章Swift闭包的多个值捕获