美文网首页
RxSwift内存管理

RxSwift内存管理

作者: silasjs | 来源:发表于2019-08-08 10:40 被阅读0次

    RxSwift内存管理

    RxSwift 是函数响应式编程的框架。使用时满屏都是函数、闭包。那么多闭包,岂不是到处都是循环引用的陷阱?怎么来检查是否有内存泄漏呢?

    RxSwift 在很多基类的构造函数和析构函数中做了埋点统计。

    public class Observable<Element> : ObservableType {
        init() {
    #if TRACE_RESOURCES
            _ = Resources.incrementTotal()
    #endif
        }
        
        deinit {
    #if TRACE_RESOURCES
            _ = Resources.decrementTotal()
    #endif
        }
    }
    

    但是,需要定义TRACE_RESOURCES后才有效。在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
    

    修改后记得pod update,然后就可以通过RxSwift.Resources.total来读取当前的引用计数了。

    如果引用计数不平衡,就该分析代码有没循环引用的地方,循环引用无非就是我引用你,你引用我,最后扯不开的那种。这里也有闭包中的循环引用方面简单的解决方法

    demo

    我们先从一个简单的 demo 中分析下 RxSwift 中的持有关系:

    class ViewController: UIViewController {
        var disposeBag = DisposeBag()
        var name : Any?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            Observable<Any>.create { (observer) -> Disposable in
                    observer.onNext("jack")
                    return Disposables.create()
                }.subscribe(onNext: { (e) in
                    print(e)
                }).disposed(by: disposeBag)    
        }
    }
    

    这就是个简单的订阅,ViewController 通常都会用DisposeBag来管理订阅的生命周期。

    持有关系分析

    控制器会持有一个DisposeBag,而订阅中构造的内部类都有对应的Disposable来负责销毁,Disposable最后是通过disposed(by:)insertDisposeBag中的。所以,Disposable持有的,控制器都通过DisposeBag也持有了。

    我们需要知道Disposable都持有了什么,才能避免在使用控制器对象的时候形成闭环引用。

    序列的创建

    RxSwift核心逻辑中我们知道,序列在创建的时候其实做的事情很少:

    1. 创建可观察序列AnonymousObservable
    2. 保存create闭包

    这部分只有序列持有着create闭包,也就是_subscribeHandler

    那么,在create闭包使用self是不会有循环引用问题的。如果self也持有着序列,就不行了。

    序列的订阅

    之前学习RxSwift销毁者,对销毁流程已经很熟悉了。订阅函数返回的其实是个BinaryDisposableBinaryDisposabledispose的时候,主要是在销毁sink,其他的Disposable,有闭包的,在销毁时就顺带回调一下。结合之前所学,可以得出下图的持有关系:

    持有关系图.jpg

    简单来说就是:

    • self持有bag
    • bag持有sink
    • sink持有观察者
    • 观察者持有_eventHandler
    • _eventHandler中使用self就需要注意了!

    所以,在_eventHandler中使用self是很危险的,也是经常需要使用self的地方,需要破开闭环。

    循环引用的问题,除了通常的弱引用外,RxSwift 也有很多种方式都可以销毁,这样循环引用的闭环也就破了:

    • 合理使用DisposeBag
    • 发出.completed.error
    • 调用dispose
    • .takeUntil(deallocated)

    平时开发中有很多的造成循环引用的场景,这里就不列举了,对框架源码有一定的了解,再加上程序中自己更加熟悉的代码,可以轻松避免循环引用的问题。

    相关文章

      网友评论

          本文标题:RxSwift内存管理

          本文链接:https://www.haomeiwen.com/subject/bjvtjctx.html