温馨提示:
本文纯属代码洁癖患者搞事情!
本文关键字:
AssociatedObject
RxSwift
对于NSObject
在RxSwift
中disposeBag
的扩展,已有解决方案,就是NSObject+Rx
。那么为什么还需要重复造车轮子呢?
为解决自定义UITableViewCell
或UICollectionViewCell
复用导致的button.rx.tap
重复订阅问题,通常情况下,我们需要这样做:
var disposeBag = DisposeBag()
override func prepareForReuse() {
super.prepareForReuse()
// Reallocate dispose bag to avoid multi subscribers
self.disposeBag = DisposeBag()
}
而使用NSObject+Rx
,我们只需要self.rx.disposeBag
即可自动且优雅的创建disposeBag
。然而,self.rx.disposeBag = DisposeBag()
会导致Xcode报错:
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)
}
}
}
}
进而,我们看一下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
的声明了吗?没错,是let
!
这样一来,想要优雅地为rx
添加一个disposeBag
是办不到了,只能退而求其次,为类本身添加一个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
扩展,避免重复造车轮子:
override func prepareForReuse() {
super.prepareForReuse()
// Reallocate dispose bag to avoid multi subscribers
var mutableSelf = self
mutableSelf.rx.disposeBag = DisposeBag()
}