NSObject添加disposeBag扩展

温馨提示:
本文纯属代码洁癖患者搞事情!

本文关键字:

AssociatedObject RxSwift

对于NSObjectRxSwiftdisposeBag的扩展,已有解决方案,就是NSObject+Rx。那么为什么还需要重复造车轮子呢?

为解决自定义UITableViewCellUICollectionViewCell 复用导致的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 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(_ 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()
}

你可能感兴趣的:(NSObject添加disposeBag扩展)