Swift开发进阶RxSwiftiOS 进阶开发

RxSwift-爬过的坑

2019-08-10  本文已影响2人  Cooci_和谐学习_不急不躁

RxSwift是一个非常好用的框架,如果你喜欢用Swift开发,那么RxSwift是你不二的选择,函数响应式的结果,让你的代码飞起来!在上瘾RxSwift给我们带来的便捷的同时,经常也会出现一些致命的坑,让你怎么也爬不出去,难受的一匹....归其本质:你还是对RxSwift不够了解,如果你想玩好RxSwift,不妨花点时间静下心来研究一下底层!这一篇文章给大家介绍几点,平时在使用RxSwift经常会遇到的坑

RxSwift计数问题

首先有两个页面LGHomeViewController 首页LGDetialViewController 详情,详情页面给首页进行传值,我们可以通过序列传递,达到你意想不到的快感,看代码

LGDetialViewController 中

// 内部序列响应,不被外界影响
fileprivate var mySubject = PublishSubject<Any>()
var publicOB : Observable<Any>{
    return mySubject.asObservable()
}

LGHomeViewController 中

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let vc = LGDetialViewController()
    vc.publicOB
    .subscribe(onNext: { (item) in
        print("订阅到 \(item)")
    })
        .disposed(by: disposeBag)
    self.navigationController?.pushViewController(vc, animated: true)
}

上面的代码乍一看没有什么问题,其实不然,这个过程不断往首页disposeBag添加订阅事件,会导致计数不断增加,就是性能消耗

*****LGDetialViewController出现了:RxSwift的引用计数: 37
****************************************
<_01_RxSwift-内存管理.LGDetialViewController: 0x7fa966414de0>走了 
销毁了
<_01_RxSwift-内存管理.LGPerson: 0x600001c8c6c0>销毁释放
text = Optional("Cooci")
*****LGDetialViewController出现了:RxSwift的引用计数: 38
****************************************
<_01_RxSwift-内存管理.LGDetialViewController: 0x7fa96665d280>走了 
销毁了
<_01_RxSwift-内存管理.LGPerson: 0x600001c93780>销毁释放
text = Optional("Cooci")
*****LGDetialViewController出现了:RxSwift的引用计数: 39
****************************************

解决办法
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    // 页面要退出,及时完成以便调用dispose
    mySubject.onCompleted()
}

因为调用序列的完成函数,就会导致我们的序列一次性,下次就无法响应
解决办法:重新激活

fileprivate var mySubject = PublishSubject<Any>()
var publicOB : Observable<Any>{
     // 重置激活
    mySubject = PublishSubject<Any>()
    return mySubject.asObservable()
}

cell复用导致序列重复订阅响应

我们实际开发中避免不了使用tableView,那么在使用过程中,经常会有一个坑:cell复用

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) as! LGTableViewCell
    
    cell.button.rx.tap
        .subscribe(onNext: { () in
            print("点击了 \(indexPath)")
        })
        .disposed(by: bag)
    return cell
}
点击了 [0, 0]
********************
点击了 [0, 1]
********************
点击了 [0, 2]
********************
点击了 [0, 1]
点击了 [0, 21]
********************
点击了 [0, 3]
点击了 [0, 23]
********************
点击了 [0, 29]
点击了 [0, 49]
点击了 [0, 69]
********************

解决思路

// 外界订阅处理
cell.button.rx.tap
    .subscribe(onNext: { () in
        print("点击了 \(indexPath)")
    })
    .disposed(by: cell.disposeBag)

// cell内部处理
override func prepareForReuse() {
    super.prepareForReuse()
    // 销毁垃圾袋重置
    disposeBag = DisposeBag()
}
class LGCustomCell: UITableViewCell{
var disposeBag = DisposeBag() 
override func prepareForReuse() {
        super.prepareForReuse()

        disposeBag = DisposeBag() 
    }
}

作为一个牛逼的开发人员,每每想到在tableView中处理响应都需要重写prepareForReuse,我就觉得难受,此刻我要勇敢的说:RxSwift其实你可以更好

于是我带着不将就的心态构建我们的思路三和思路四

extension Reactive where Base: UITableViewCell {
    // 提供给外界重用序列
    public var prepareForReuse: RxSwift.Observable<Void> {
        var prepareForReuseKey: Int8 = 0
        if let prepareForReuseOB = objc_getAssociatedObject(base, &prepareForReuseKey) as? Observable<Void> {
            return prepareForReuseOB
        }
        let prepareForReuseOB = Observable.of(
            sentMessage(#selector(Base.prepareForReuse)).map { _ in }
            , deallocated)
            .merge()
        objc_setAssociatedObject(base, &prepareForReuseKey, prepareForReuseOB, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)

        return prepareForReuseOB
    }
    // 提供一个重用垃圾回收袋
    public var reuseBag: DisposeBag {
        MainScheduler.ensureExecutingOnScheduler()
        var prepareForReuseBag: Int8 = 0
        if let bag = objc_getAssociatedObject(base, &prepareForReuseBag) as? DisposeBag {
            return bag
        }
        
        let bag = DisposeBag()
        objc_setAssociatedObject(base, &prepareForReuseBag, bag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        
        _ = sentMessage(#selector(Base.prepareForReuse))
            .subscribe(onNext: { [weak base] _ in
                let newBag = DisposeBag()
                guard let base = base else {return}
                objc_setAssociatedObject(base, &prepareForReuseBag, newBag, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
            })
        return bag
    }
}
cell.button.rx.tap.takeUntil(cell.rx.prepareForReuse)
    .subscribe(onNext: { () in
        print("点击了 \(indexPath)")
    })
cell.button.rx.tap
    .subscribe(onNext: { () in
        print("点击了 \(indexPath)")
    })
    .disposed(by: cell.rx.reuseBag)

2019年08月10日 01:33 还在坚持把博客写完,这一年一直在不断更新博客内容(因为之前一直忙还有自己惰性都没有好好更新)看到很多博主都是粉丝几千,内心也难免失落。悟已往之不谏,知来者之可追! 接下来会持续努力和大家一起共建iOS生态强盛。我还是我,颜色不一样的烟火,我是Cooci,我为自己带盐!

上一篇下一篇

猜你喜欢

热点阅读