RxSwift 6 Filter Operator 實操

1 優(yōu)化現(xiàn)有應(yīng)用

前面一章引入了 RxSwift 中的函數(shù)式編程的方面, 即 Operator.

下面就來使用之前學(xué)過的一些過濾型操作符, 看看在實際工程中如何使用它們.

當然下面的這些代碼只是引路作用, 并非是進入所謂的 "操作符最佳實踐". 先入門, 然后再慢慢提高優(yōu)化!

2 共享 Observable 序列, 實現(xiàn)一些過濾操作

先來看一個情況:

let numbers = Observable<Int>.create { observer in
    let start = getStartNumber()
    observer.onNext(start)
    observer.onNext(start+1)
    observer.onNext(start+2)
    observer.onCompleted()
    return Disposables.create()
}

getStartNumber() 方法是這樣的:

var start = 0
func getStartNumber() -> Int {
start += 1
    return start
}

下面對該序列進行觀察.

numbers
  .subscribe(onNext: { el in
    print("element [\(el)]")
  }, onCompleted: {
    print("-------------")
  })

如果多次觀察這段代碼, 最后的輸出會在每次觀察的時候都不一樣.

這是為什么呢?

因為每次觀察者開始觀察的時候, 都會去執(zhí)行 Create 塊中的代碼, 從而導(dǎo)致序列的變化.

有時這樣的變化是有意為之, 但有時卻不希望發(fā)生.

如果不希望每次觀察都是去重新執(zhí)行 create 塊, 則可以使用 share() 操作符.

let newPhotos = photosViewController.selectedPhotos
  .share()

這樣的話, 任何在 newPhotos 上的新觀察者得到的都是同樣的可觀察序列.

實際上的原理是這樣的: 當序列的觀察者數(shù)量從 0 變化到 1 的時候, share 會去創(chuàng)建一個 Observable 序列出來. 當觀察者再增加時, share 則會直接使用已創(chuàng)建的序列交給觀察者. 如果在該序列上的所有觀察者都被釋放了. 則 share 會將創(chuàng)建出來的序列銷毀. 而如果后面又有新的觀察者, 則又會重復(fù)上述過程.

另外 share 操作符有一個特性, 即它不會提供在觀察者開始觀察之前序列已發(fā)射的內(nèi)容. 如果需要 share 的共享特性, 又需要知道最后一個發(fā)射的內(nèi)容, 則可以使用 shareReply(_) 操作符, 它可以指定一個緩存, 緩存之前發(fā)射過的若干事件.

2.1 ignoreElments 操作符

這個操作符的作用是只允許 complete 或 error 通過. 這樣的話, 就可以用來觀察完成或是錯誤. 當然這里只是一個假設(shè)的使用情況, 不對 next 事件作出響應(yīng)也是一個結(jié)果.

2.2 實現(xiàn)過濾掉相同圖片的功能

另外如果想添加照片的時候只添加不同的文件名的圖片, 則也可以使用過濾.

但是多個 UIImage 對象間的區(qū)別不能通過地址來識別, 也無法通過名字或 URL 識別.(除非是自定義的子類. 實際使用的時候就可以繼承并在子類中添加類似屬性用于識別不同的 Image.)

不過在本例中僅使用字節(jié)長度作為判斷依據(jù), 防止跑題.

newPhoto
    .filter({ newImage in
        // 過濾豎向的圖片.
        newImage.size.width > newImage.size.height
    })
    .filter({ [weak self] newImage in
        // 過濾相同大小的圖片, 防止重復(fù)選擇
        let len = UIImagePNGRepresentation(newImage)?.count ?? 0
        guard self?.imageCache.contains(len) == false else { return false }
        self?.imageCache.append(len)
        return true
    })
    .subscribe(onNext: { [weak self] newImage in
        guard let images = self?.images else { return }
        images.value.append(newImage)
        }, onDisposed: {
            print("completed photo selection")
    })
    .addDisposableTo(photosViewController.bag)

2.3 實現(xiàn)當只有滿足條件時才會允許 next 消息通過

這里需要使用 takeWhile 操作符. 可以為 takeWhile 提供一個布爾判斷, 如果值變?yōu)榧僦? 就可以取消掉之后的所有元素.

newPhoto
    .takeWhile({ [weak self] _ in
        return (self?.images.value.count ?? 0) < 6
    })
    // ... 下面還是之前的過濾代碼等內(nèi)容

這樣一來, 條件為 false 的時候, 就不會允許 next 通過了.

3 優(yōu)化照片選擇器

下面首先來構(gòu)造一個自定義 observable, 然后通過不同的過濾器來操作它, 提升用戶體驗:

這個 observable 是針對某個權(quán)限的請求和允許情況的:

import Foundation
import Photos
import RxSwift

extension PHPhotoLibrary {
    static var authorized: Observable<Bool> {
        return Observable.create({ observer in
            DispatchQueue.main.async {
                if authorizationStatus() == .authorized {
                    observer.onNext(true)
                    observer.onCompleted()
                } else {
                    observer.onNext(false)
                    requestAuthorization({ status in
                        observer.onNext(status == .authorized)
                        observer.onCompleted()
                    })
                }
            }
            return Disposables.create()
        })
    }
}

上面的代碼中, 當外界有新的觀察者開始觀察的時候, 都會觸發(fā) create 方法的執(zhí)行. 所以每次都會去判斷權(quán)限.

使用 DispatchQueue.main.async 的意思是: 首先 DispatchQueue.main 表示在主線程中執(zhí)行, 而 DispatchQueue.global() 是在后臺線程中執(zhí)行, 且 sync 表示當前線程會等待該工作塊的執(zhí)行完畢后再繼續(xù)執(zhí)行, 而 async 的話, 當前線程不會等待該工作塊的執(zhí)行完畢.

sync 方式執(zhí)行的工作塊, 當前線程會等待該工作塊執(zhí)行完畢后再繼續(xù)執(zhí)行. 而 async 方式執(zhí)行的工作塊當前線程是不會等待它結(jié)束的.

3.1 開始外界的觀察操作

下面就在外界開始觀察, 若權(quán)限是允許的情況下, 則重新加載照片.

由于權(quán)限的請求只能一次, 故當前狀態(tài)有兩種:

  • 用戶第一次運行程序, 第一次請求權(quán)限, 且點擊的是 ok.

    false---true---completed

  • 之后的運行過程, 如果之前允許過該權(quán)限.

    true---completed

經(jīng)過分析, 我們知道要重新加載照片的前提就是遇到 true, 而 true 的事件肯定是最后一個 next 事件.

下面就開始觀察:

let authorized = PHPhotoLibrary.authorized.share()
authorized.skipWhile({ elem in
    elem == false
}).take(1).subscribe(onNext: { [weak self] _ in
    self?.photos = PhotosViewController.loadPhotos()
    DispatchQueue.main.async {
        self?.collectionView?.reloadData()
    }
}).addDisposableTo(bag)

不過在 RxSwift 中盡可能不要使用 GCD 來切換線程, 更多地是使用 scheduler 來達到目的. 詳見 15章.

3.2 當用戶不允許時顯示錯誤信息

每次這樣的情況都需要先分析好當前的 Observable 中的事件序列是個什么樣的情況.

4 利用時間的操作符

略看.

第六章結(jié)束.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涡贱,一起剝皮案震驚了整個濱河市犬庇,隨后出現(xiàn)的幾起案子腿箩,更是在濱河造成了極大的恐慌掉瞳,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舞竿,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機坯汤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搀愧,“玉大人惰聂,你說我怎么就攤上這事≡凵福” “怎么了搓幌?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長迅箩。 經(jīng)常有香客問我溉愁,道長,這世上最難降的妖魔是什么饲趋? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任拐揭,我火速辦了婚禮,結(jié)果婚禮上奕塑,老公的妹妹穿的比我還像新娘堂污。我一直安慰自己,他們只是感情好龄砰,可當我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布盟猖。 她就那樣靜靜地躺著,像睡著了一般寝贡。 火紅的嫁衣襯著肌膚如雪扒披。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天圃泡,我揣著相機與錄音碟案,去河邊找鬼。 笑死颇蜡,一個胖子當著我的面吹牛价说,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播风秤,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼鳖目,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缤弦?” 一聲冷哼從身側(cè)響起领迈,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后狸捅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷蜓,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年尘喝,在試婚紗的時候發(fā)現(xiàn)自己被綠了磁浇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡朽褪,死狀恐怖置吓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缔赠,我是刑警寧澤衍锚,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站橡淑,受9級特大地震影響构拳,放射性物質(zhì)發(fā)生泄漏咆爽。R本人自食惡果不足惜梁棠,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斗埂。 院中可真熱鬧符糊,春花似錦、人聲如沸呛凶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漾稀。三九已至模闲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間崭捍,已是汗流浹背尸折。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留殷蛇,地道東北人实夹。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像粒梦,于是被迫代替她去往敵國和親亮航。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理匀们,服務(wù)發(fā)現(xiàn)缴淋,斷路器,智...
    卡卡羅2017閱讀 134,693評論 18 139
  • 本篇文章介主要紹RxJava中操作符是以函數(shù)作為基本單位,與響應(yīng)式編程作為結(jié)合使用的重抖,對什么是操作圆存、操作符都有哪些...
    嘎啦果安卓獸閱讀 2,864評論 0 10
  • 參考:給 Android 開發(fā)者的 RxJava 詳解-扔物線深入淺出RxJava 基礎(chǔ) "a library f...
    Vincen1024閱讀 545評論 0 1
  • 最近在學(xué)習RxSwift相關(guān)的內(nèi)容,在這里記錄一些基本的知識點仇哆,以便今后查閱沦辙。 Observable 在RxSwi...
    L_Zephyr閱讀 1,762評論 1 4
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,264評論 25 707