RxSwift(13)—— 爬過的坑

就問此時此刻還有誰奋救?45度仰望天空,該死反惕!我這無處安放的魅力尝艘!


RxSwift目錄直通車--- 和諧學習,不急不躁姿染!


RxSwift是一個非常好用的框架背亥,如果你喜歡用Swift開發(fā),那么RxSwift是你不二的選擇,函數(shù)響應式的結果狡汉,讓你的代碼飛起來娄徊!在上癮RxSwift給我們帶來的便捷的同時,經常也會出現(xiàn)一些致命的坑盾戴,讓你怎么也爬不出去寄锐,難受的一匹....歸其本質:你還是對RxSwift不夠了解片仿,如果你想玩好RxSwift杀餐,不妨花點時間靜下心來研究一下底層颁糟!這一篇文章給大家介紹幾點遵馆,平時在使用RxSwift經常會遇到的坑

RxSwift計數(shù)問題

首先有兩個頁面LGHomeViewController 首頁LGDetialViewController 詳情,詳情頁面給首頁進行傳值,我們可以通過序列傳遞芍阎,達到你意想不到的快感躁绸,看代碼

LGDetialViewController 中

// 內部序列響應吮铭,不被外界影響
fileprivate var mySubject = PublishSubject<Any>()
var publicOB : Observable<Any>{
    return mySubject.asObservable()
}
  • 對外暴露publicOB,以便訂閱信息
  • mySubject序列響應矛渴,內部事件發(fā)送
  • 內外區(qū)分,達到干凈的效果

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)
}
  • 首頁響應push到詳情頁面去
  • 訂閱內部響應事件惫搏,以便處理事務

上面的代碼乍一看沒有什么問題具温,其實不然,這個過程不斷往首頁disposeBag添加訂閱事件筐赔,會導致計數(shù)不斷增加铣猩,就是性能消耗

*****LGDetialViewController出現(xiàn)了:RxSwift的引用計數(shù): 37
****************************************
<_01_RxSwift-內存管理.LGDetialViewController: 0x7fa966414de0>走了 
銷毀了
<_01_RxSwift-內存管理.LGPerson: 0x600001c8c6c0>銷毀釋放
text = Optional("Cooci")
*****LGDetialViewController出現(xiàn)了:RxSwift的引用計數(shù): 38
****************************************
<_01_RxSwift-內存管理.LGDetialViewController: 0x7fa96665d280>走了 
銷毀了
<_01_RxSwift-內存管理.LGPerson: 0x600001c93780>銷毀釋放
text = Optional("Cooci")
*****LGDetialViewController出現(xiàn)了:RxSwift的引用計數(shù): 39
****************************************
  • 可以清晰的看到:計數(shù)由37-38-39

解決辦法
  • 思路一:最直接不加入垃圾銷毀袋
  • 思路二:我們分析因為,當前首頁沒有釋放導致首頁的銷毀垃圾袋不斷增多茴丰!
    換一個垃圾銷毀袋
  • 思路三: 我們通過前面的銷毀流程达皿,可以直接調用complete或者error信號達到 :及時回收,這樣就不至于一直存在首頁的垃圾袋中
override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    // 頁面要退出,及時完成以便調用dispose
    mySubject.onCompleted()
}

因為調用序列的完成函數(shù)贿肩,就會導致我們的序列一次性峦椰,下次就無法響應
解決辦法:重新激活

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

cell復用導致序列重復訂閱響應

我們實際開發(fā)中避免不了使用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
}
  • 這一段代碼乍一看也是沒有什么問題的汰规,包括你不滑動屏幕也不會產生問題
  • 只要你一劃動屏幕汤功,因為我們的cell的重用機制,會導致cell.button.rx.tap的訂閱也會重復訂閱響應溜哮,顯然不是我們正常開發(fā)中想見到的樣子
點擊了 [0, 0]
********************
點擊了 [0, 1]
********************
點擊了 [0, 2]
********************
點擊了 [0, 1]
點擊了 [0, 21]
********************
點擊了 [0, 3]
點擊了 [0, 23]
********************
點擊了 [0, 29]
點擊了 [0, 49]
點擊了 [0, 69]
********************

解決思路

  • 思路一: 把主動銷毀的能力收回滔金,銷毀垃圾袋交給我們的cell.disposeBag,在我們重用響應的時候,及時銷毀茂嗓,重置餐茵!
// 外界訂閱處理
cell.button.rx.tap
    .subscribe(onNext: { () in
        print("點擊了 \(indexPath)")
    })
    .disposed(by: cell.disposeBag)

// cell內部處理
override func prepareForReuse() {
    super.prepareForReuse()
    // 銷毀垃圾袋重置
    disposeBag = DisposeBag()
}
  • 銷毀垃圾袋交給cell自身

  • prepareForReuse 響應的時候,銷毀垃圾袋重置

  • 效果很明顯述吸,問題得到了解決忿族!

  • 思路二:基類封裝

class LGCustomCell: UITableViewCell{
var disposeBag = DisposeBag() 
override func prepareForReuse() {
        super.prepareForReuse()

        disposeBag = DisposeBag() 
    }
}
  • 把相關重用方法和我們垃圾袋封裝在基類,這樣就大大節(jié)省人力咯!

作為一個牛逼的開發(fā)人員肠阱,每每想到在tableView中處理響應都需要重寫prepareForReuse,我就覺得難受票唆,此刻我要勇敢的說:RxSwift其實你可以更好

于是我?guī)е粚⒕偷男膽B(tài)構建我們的思路三和思路四

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
    }
}
  • 重用響應prepareForReuse,只要發(fā)現(xiàn)我們的cell已發(fā)生重用,通過RxSwift就會接受到一個重用序列的響應屹徘,起到綁定效果
  • 這里還合并了cell的銷毀序列走趋,畢竟cell都銷毀了也就沒有任何響應的意義
cell.button.rx.tap.takeUntil(cell.rx.prepareForReuse)
    .subscribe(onNext: { () in
        print("點擊了 \(indexPath)")
    })
  • 通過takeUntil限定了button的點擊響應能力
cell.button.rx.tap
    .subscribe(onNext: { () in
        print("點擊了 \(indexPath)")
    })
    .disposed(by: cell.rx.reuseBag)
  • 思路四:就是通過把此次響應加入到特定的銷毀袋,這個銷毀袋通過關聯(lián)屬性的方式保證了一定的性能噪伊,同時這個銷毀袋是觀察了cell的重寫響應簿煌,一旦有重寫那么就直接銷毀重置,達到自動重置效果
  • 思路三&思路四都是基于最初的思路不夠構建鉴吹,目的也是為了:Write once, run anywhere

2019年08月10日 01:33 還在堅持把博客寫完姨伟,這一年一直在不斷更新博客內容(因為之前一直忙還有自己惰性都沒有好好更新)看到很多博主都是粉絲幾千,內心也難免失落豆励。悟已往之不諫夺荒,知來者之可追! 接下來會持續(xù)努力和大家一起共建iOS生態(tài)強盛良蒸。我還是我技扼,顏色不一樣的煙火,我是Cooci,我為自己帶鹽嫩痰!

就問此時此刻還有誰剿吻?45度仰望天空,該死串纺!我這無處安放的魅力丽旅!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纺棺,隨后出現(xiàn)的幾起案子榄笙,更是在濱河造成了極大的恐慌,老刑警劉巖五辽,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件办斑,死亡現(xiàn)場離奇詭異,居然都是意外死亡杆逗,警方通過查閱死者的電腦和手機乡翅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罪郊,“玉大人蠕蚜,你說我怎么就攤上這事』陂希” “怎么了靶累?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵腺毫,是天一觀的道長。 經常有香客問我挣柬,道長潮酒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任邪蛔,我火速辦了婚禮急黎,結果婚禮上,老公的妹妹穿的比我還像新娘侧到。我一直安慰自己勃教,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布匠抗。 她就那樣靜靜地躺著故源,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汞贸。 梳的紋絲不亂的頭發(fā)上绳军,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音矢腻,去河邊找鬼删铃。 笑死,一個胖子當著我的面吹牛踏堡,可吹牛的內容都是我干的。 我是一名探鬼主播咒劲,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼顷蟆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腐魂?” 一聲冷哼從身側響起帐偎,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛔屹,沒想到半個月后削樊,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡兔毒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年漫贞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片育叁。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡迅脐,死狀恐怖,靈堂內的尸體忽然破棺而出豪嗽,到底是詐尸還是另有隱情谴蔑,我是刑警寧澤豌骏,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站隐锭,受9級特大地震影響窃躲,放射性物質發(fā)生泄漏。R本人自食惡果不足惜钦睡,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一蒂窒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赎婚,春花似錦刘绣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撩嚼,卻和暖如春停士,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背完丽。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工恋技, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逻族。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓蜻底,卻偏偏與公主長得像,于是被迫代替她去往敵國和親聘鳞。 傳聞我的和親對象是個殘疾皇子薄辅,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,089評論 1 32
  • 本文章內部分圖片資源來自RayWenderlich.com 本文結合自己的理解來總結介紹一下RxSwift最基本的...
    FKSky閱讀 2,856評論 4 14
  • RxSwift是由序列,觀察者,調度者,銷毀者組成】倭В可見,銷毀者在RxSwift的重要性站楚。了解銷毀者,才能更好的了...
    king_jensen閱讀 648評論 0 2
  • 聆尋/文 順天有個人叫馬子才,人們都知他對菊花情有獨鐘搏嗡,常常為了新菊種不拒千里去四處求購窿春。 一天,他揣著在金陵購得...
    聆尋閱讀 599評論 0 1
  • 干紅盛采盒,枯黃落旧乞,聽怕深秋吹角。衣忒薄纽甘,夜風寒良蛮,那知桐葉殘。 人不易悍赢,天未白决瞳,繾綣更為遠客货徙。一片片,一聲聲皮胡,凄清燕趙行痴颊。
    林香砌閱讀 308評論 2 6