
溫馨提示:
本文純屬代碼潔癖患者搞事情!
本文關(guān)鍵字:
AssociatedObject RxSwift
對(duì)于NSObject在RxSwift中disposeBag的擴(kuò)展,已有解決方案,就是NSObject+Rx。那么為什么還需要重復(fù)造車輪子呢?
為解決自定義UITableViewCell或UICollectionViewCell 復(fù)用導(dǎo)致的button.rx.tap 重復(fù)訂閱問題,通常情況下,我們需要這樣做:
var disposeBag = DisposeBag()
override func prepareForReuse() {
super.prepareForReuse()
// Reallocate dispose bag to avoid multi subscribers
self.disposeBag = DisposeBag()
}
而使用NSObject+Rx,我們只需要self.rx.disposeBag 即可自動(dòng)且優(yōu)雅的創(chuàng)建disposeBag 。然而,self.rx.disposeBag = DisposeBag() 會(huì)導(dǎo)致Xcode報(bào)錯(cuò):
Cannot assign to property: 'self' is immutable
我們先來看一下NSObject+Rx的源碼:
public extension Reactive where Base: AnyObject {
/// a unique DisposeBag that is related to the Reactive.Base instance only for Reference type
public var disposeBag: DisposeBag {
get {
return synchronizedBag {
if let disposeObject = objc_getAssociatedObject(base, &disposeBagContext) as? DisposeBag {
return disposeObject
}
let disposeObject = DisposeBag()
objc_setAssociatedObject(base, &disposeBagContext, disposeObject, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return disposeObject
}
}
set {
synchronizedBag {
objc_setAssociatedObject(base, &disposeBagContext, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
}
進(jìn)而,我們看一下RxSwift的源碼:
public struct Reactive<Base> {
/// Base object to extend.
public let base: Base
/// Creates extensions with base object.
///
/// - parameter base: Base object.
public init(_ base: Base) {
self.base = base
}
}
注意到base的聲明了嗎?沒錯(cuò),是let !
這樣一來,想要優(yōu)雅地為rx添加一個(gè)disposeBag是辦不到了,只能退而求其次,為類本身添加一個(gè)rx_disposeBag屬性:
/// AssociatedKeys
private struct AssociatedKeys {
static var disposeBag = "disposeBag"
}
/// Synchronizing
/// - Parameter action: Closure
/// - Returns: Action result
func synchronized<T>(_ action: () -> T) -> T {
objc_sync_enter(self)
let result = action()
objc_sync_exit(self)
return result
}
/// Stored disposeBag
public var rx_disposeBag: DisposeBag {
get {
self.synchronized {
if let disposeBag = objc_getAssociatedObject(self, &AssociatedKeys.disposeBag) as? DisposeBag {
return disposeBag
}
let disposeBag = DisposeBag()
objc_setAssociatedObject(self, &AssociatedKeys.disposeBag, disposeBag, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
return disposeBag
}
}
set {
self.synchronized {
objc_setAssociatedObject(self, &AssociatedKeys.disposeBag, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
這里還有另外一種方法,依舊使用NSObject+Rx擴(kuò)展,避免重復(fù)造車輪子:
override func prepareForReuse() {
super.prepareForReuse()
// Reallocate dispose bag to avoid multi subscribers
var mutableSelf = self
mutableSelf.rx.disposeBag = DisposeBag()
}