一、RxSwift内存办理

1.observeWeakly

接下来咱们来看一个比如:

        self.person.rx.observe(String.self, "name")
      .subscribe(onNext: { change in
        print("observe订阅到了KVO:\(String(describing: change))")
      }).disposed(by: disposeBag)
    self.person.rx.observeWeakly(String.self, "name")
      .subscribe(onNext: { change in
        print("observeWeakly订阅到了KVO:\(String(describing: change))")
      }).disposed(by: disposeBag)

看到了两个不同的observe observeWeakly,别离订阅了name的change。

observe和observeWeakly 有什么区别吗?

1.observe有可能会呈现开释不洁净的状况
2.observeWeakly连weak一同监听处理开释不洁净的状况

进入源码检查:

iOS探索RxSwift之内存管理
再次进入observeWeaklyKeyPathFor:

    private func observeWeaklyKeyPathFor(_ target: NSObject, keyPath: String, options: KeyValueObservingOptions) -> Observable<AnyObject?> {
    let components = keyPath.components(separatedBy: ".").filter { $0 != "self" }
    let observable = observeWeaklyKeyPathFor(target, keyPathSections: components, options: options)
      .finishWithNilWhenDealloc(target)
    if !options.isDisjoint(with: .initial) {
      return observable
    }
    else {
      return observable
        .skip(1)
    }
  }

切割字符components 在传入observeWeaklyKeyPathFor 处理返回序列。断点调试看看:

iOS探索RxSwift之内存管理
获取到propertyName特点称号,propertyAttributes 特点的具体pointervalue。在经过isWeakProperty 判别是否是弱引证声明。在注册KVOObservable 特点监听。
iOS探索RxSwift之内存管理
在propertyObservable.flatMapLatest接纳KVOObservable特点变化监听的回调的容错处理。
iOS探索RxSwift之内存管理
这里留意先履行.subscribe订阅闭包 在履行.flatMapLatest闭包。

进入KVOObservable代码:

iOS探索RxSwift之内存管理
KVOObservable承继ObservableType完成KVOObservableProtocol协议,保存特点,循环订阅特点音讯on(.next)

2.RxSwift-KVO流程

现在咱们看KVOObserver 类,KVOObservable->subscribe->KVOObserver(parent: self)做了什么。

private final class KVOObserver
  : _RXKVOObserver
  , Disposable {
  typealias Callback = (Any?) -> Void
  var retainSelf: KVOObserver?
  init(parent: KVOObservableProtocol, callback: @escaping Callback) {
    #if TRACE_RESOURCES
      _ = Resources.incrementTotal()
    #endif
    super.init(target: parent.target, retainTarget: parent.retainTarget, keyPath: parent.keyPath, options: parent.options.nsOptions, callback: callback)
    self.retainSelf = self
  }
  override func dispose() {
    super.dispose()
    self.retainSelf = nil
  }
  deinit {
    #if TRACE_RESOURCES
      _ = Resources.decrementTotal()
    #endif
  }
}

_RXKVOObserver->承继NSObject为什么呢?

第一个想到的是获取目标的特点参数,得到元类信息。

第二个这个可能是个中心类,对rx的特点path进行调查(调查者移送)。

在看super.init->_RXKVOObserver.init

iOS探索RxSwift之内存管理
进入断点调试
iOS探索RxSwift之内存管理
从断点上看”student.nickName”订阅了两次,一层一层的订阅,在_RXKVOObserver进行KVO特点监听。 然后发现observeWeaklyKeyPathFor是一个递归调用的办法。

so:回到最初的observeWeakly便是底层完成了KVO对特点的监听。

3.Rx内存办理

然后咱们在回到KVOObservable代码看到:

iOS探索RxSwift之内存管理
_RXKVOObserver在内部也是弱引证接纳target
iOS探索RxSwift之内存管理
unowned var 便是oc中的 unsafe_unretained 相同效果。(为什么用unsafe_unretained而不是weak呢)因为性能更高。

现在咱们看一个比如:

        myClosure = { [weak self] in
      self?.name = "NY"
    }
    self.myClosure!()
    deinit {
    print("\(self)销毁 VC")
  }

上面代码假如不加[weak self]会发生循环引证,这个是基本状况。那假如呈现其他状况呢?

也能够把weak换成unowned也能处理循环引证。

iOS探索RxSwift之内存管理

        myClosure = { [weak self] in
      DispatchQueue.global().asyncAfter(deadline: .now()+2) {
        self?.name = "NY"
        print(self?.name as Any)
      }
    }

修正代码添加异步推迟操作2秒,在赋值打印运转程序。

iOS探索RxSwift之内存管理

咱们发现并没有崩溃,也没有报错。只是打印nil,可是这个成果并不友好,不利于咱们发现问题。

这么处理nil问题呢,这个代码咱们都会的。再次声明self 为强引证

    guard let self = self else { return }   //4.2版别之后 保留关键
    self.name = "NY"
    print(self.name as Any)

iOS探索RxSwift之内存管理

接下来在看一个比如:

self.accountTF.rx.text.orEmpty
      .subscribe(onNext:{ text in
        self.title = text
      }).disposed(by: disposeBag)

会发生循环引证吗?

iOS探索RxSwift之内存管理
没有输出销毁VC,这段代码发生了循环引证!!!具体是为什么呢?

修正代码添加 [weak self]

self.accountTF.rx.text.orEmpty
      .subscribe(onNext:{ [weak self]text in
        self?.title = text
      }).disposed(by: disposeBag)

看到运转成果,销毁了VC而且rx计数归0。

iOS探索RxSwift之内存管理
核心问题:
那么RX的引证计数是在什么时分销毁归0的呢?

咱们在DisposeBase中设置断点,运转运转代码调试.

iOS探索RxSwift之内存管理
在首页显现,VC销毁之后rx在进行引证计数减法。

继续修正代码:

self.accountTF.rx.text.orEmpty
      .bind(to: self.rx.title)
      .disposed(by: disposeBag)

这样修正后的代码会发生循环引证吗?

iOS探索RxSwift之内存管理
看打印就现已知道,这样修正后没有发生循环引证。为什么呢?rxswift内部是这么处理的呢?

在经过一个比如研究一下:

self.observable = Observable<Any>.create { anyObserver -> Disposable in
      anyObserver.onNext("Hello World")
      print(self)
      return Disposables.create()
    }
   
    self.observable?.subscribe(onNext: {
      print("订阅到了:\($0) --")
    }).disposed(by: self.disposeBag)

在创立序列时打印print(self),这里会发生循环引证吗?

iOS探索RxSwift之内存管理
答案是会发生循环引证,并没有销毁VC。 self->observable->create{}->self

这步要留意.subscribe中调用print(self)也会循环引证。

iOS探索RxSwift之内存管理

继续看代码:

Observable<Any>.create { anyObserver -> Disposable in
      self.observer = anyObserver
      anyObserver.onNext("Hello World")
      return Disposables.create()
    }
    .subscribe(onNext: { item in
      print(self)
      print("订阅到了:\(item)")
    })
    .disposed(by: self.disposeBag)

这个代码会发生循环引证吗?

iOS探索RxSwift之内存管理
答案是会,self -> anyObserver -> subscribe -> self 所以发生了循环引证联系。

let vc = LGDetialViewController()
    vc.publicOB.subscribe(onNext:{ item in
      print("在\(self)订阅到了\(item)")
    }).disposed(by: disposeBag)

这段代码中会发生rxswift计数循环引证,并不是VC页面上的循环引证。

iOS探索RxSwift之内存管理
每次点击都会添加rx的引证计数。为什么呢?

咱们看到打印VC并没有销毁,是vc发生了循环引证。怎样处理这个问题呢?怎样销毁掉VC?

当时DetialViewController的disposed用的不应该是用VC的disposeBag。

vc.disposeBag然后在运转代码

iOS探索RxSwift之内存管理
看到了rx计数并没有累加,问处理。

或者运用_ = vc.publicOB.take(until: vc.rx.deallocated)也能处理问题,使命直到vc.rx.deallocated 详情页销毁的时分完毕。

假如当DetialViewController页是用mySubject.onCompleted()完毕,vc中运用DetialViewController的let dvc声明需要在DetialViewController页中再次激活:

mySubject = PublishSubject<Any>()//激活

总结

  1. observeWeakly:的首要递归函数observeWeaklyKeyPathFor对特点进行监听,KVOObservable是终究接纳监听特点的类。
  2. RxSwift-KVO流程:KVOObservable->subscribe->KVOObserver->_RXKVOObserver(移送调查者)-OC原生KVO
  3. Rx内存办理:unowned var 便是oc中的 unsafe_unretained 相同效果。及在RxSwift中[weak self]的运用,RxSwift本身有针对内部运用的引证计数,首要是用disposeBag来进行维护。subscribe(onNext)和subscribe{}的履行代码不相同,成果也不相同subscribe(onNext)容易呈现循环引证(要留意细节)。