(十九)RxSwift之内存管理

437 阅读2分钟

内存管理是开发中不可忽视的问题,而循环引用又是引起内存泄漏的最常见的问题。 让我们来看几个简单的问题,以及如何解决:

循环引用

var name:String?
var myClosure : (() -> Void)?
override func viewDidLoad() {
    super.viewDidLoad()
    
    myClosure = {
        self.name = "马小撂"
    }
    myClosure!()
}  

然后我们用析构函数检查是否循环引用

deinit {
    print("deinit")
}

上面的函数调用,当离开页面的时候,没有走deinit方法,self持有了myClosuremyClosure有持有了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中的weakSelfstrongSelf是一样的。

延长生命周期(guard)

myClosure = {[weak self] in
    guard let self = self else { return }
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        self.name = "马小撂"
        print(self.name!)
    }
}
myClosure!()

因为self已经被移除关键字,所以用selfstrongSelf是一样的。

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)