RxSwift 深入浅出(二)高阶函数

RxSwift 这个框架看我就够了,这一篇我重点介绍高阶函数,掌握好RxSwift的高阶函数,是你通往成功的捷径。搞RxSwift,我是认真的

RxSwift 宝图镇博,咔咔点赞~~~~

Rxswift
import Foundation

import RxSwift
import RxCocoa

class FilteringVC: UIViewController {
    
    let disposedB = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.orange
        
//        testFilter()
        testDistinctUntilChanged()
//        testSingle()
//        testElementAt()
//        testIgnoreElements()
//        testTake()
//        testTakeLast()
//        testSkip()
//        testSample()
//        testDebounce()
        
    }
    
    func testFilter(){
        //该操作符就是用来过滤掉某些不符合要求的事件。
        Observable.of(2, 30, 22, 5, 60, 3, 40 ,9)
            .filter {
                $0 > 10
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    
    func testDistinctUntilChanged(){
        //该操作符用于过滤掉连续重复的事件。
        Observable.of(2, 2, 2, 5, 60, 3, 40 ,9)
            .distinctUntilChanged()
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    
    func testSingle(){
        Observable.of(2, 30, 22, 5, 60, 3, 40 ,9)
            .filter {
                $0 > 10
            }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    
    func testElementAt(){
        //        只发送你选定的那个元素
        Observable.of(1, 2, 3, 4)
            .elementAt(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    
    func testIgnoreElements(){
//        该操作符可以忽略掉所有的元素,只发出 error或completed 事件。
//        如果我们并不关心 Observable 的任何元素,只想知道 Observable 在什么时候终止,那就可以使用 ignoreElements 操作符。
        Observable.of(1, 2, 3, 4)
            .ignoreElements()
            .subscribe{
                print($0)
            }
            .disposed(by: disposedB)
    }
    
    func testTake(){
        //   该方法实现仅发送 Observable 序列中的前 n 个事件,在满足数量之后会自动 .completed。
        Observable.of(1, 2, 3, 4)
            .take(1)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    
    func testTakeLast(){
        //   该方法实现仅发送 Observable序列中的后 n 个事件。
        Observable.of(1, 2, 3, 4)
            .takeLast(1)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    
    func testSkip(){
        //   跳过源 Observable 序列发出的前 n 个事件。
        Observable.of(1, 2, 3, 4)
            .skip(2)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
    func testSample(){
        //  通过 notifier 的事件 - 会触发  source 的响应,而如果两次 notifier 事件之间没有源序列的事件,则不发送值。
        let source = PublishSubject<Int>()
        let notifier = PublishSubject<String>()
        source.sample(notifier)
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
        source.onNext(1)
        //让源序列接收接收消息
        notifier.onNext("A")
        source.onNext(2)
        //让源序列接收接收消息
        notifier.onNext("B")
        notifier.onNext("C")
        source.onNext(3)
        source.onNext(4)
        //让源序列接收接收消息
        notifier.onNext("D")
        source.onNext(5)
        //让源序列接收接收消息
        notifier.onCompleted()
    
    }
    func testDebounce(){
//        debounce 操作符可以用来过滤掉高频产生的元素,它只会发出这种元素:该元素产生后,一段时间内没有新元素产生。
//        换句话说就是,队列中的元素如果和下一个元素的间隔小于了指定的时间间隔,那么这个元素将被过滤掉。
//        debounce 常用在用户输入的时候,不需要每个字母敲进去都发送一个事件,而是稍等一下取最后一个事件。
//
        //定义好每个事件里的值以及发送的时间
        let times = [ [ "value": 1, "time": 0.1 ],
                      [ "value": 2, "time": 1.1 ],
                      [ "value": 3, "time": 1.2 ],
                      [ "value": 4, "time": 1.2 ],
                      [ "value": 5, "time": 1.4 ],
                      [ "value": 6, "time": 2.1 ] ]
            //生成对应的 Observable 序列并订阅
        Observable.from(times)
            .flatMap { item in
                return Observable.of(Int(item["value"]!))
                    .delaySubscription(Double(item["time"]!), scheduler: MainScheduler.instance)
            }
            .debounce(0.5, scheduler: MainScheduler.instance) //只发出与下一个间隔超过0.5秒的元素
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
    }
}

上面是经常使用的高阶函数,其实和swift的高阶函数是非常类似的,下面再讲几个有意思的高阶函数

class ViewController: UIViewController {

    let disposedB = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()

//        testBuffer()
//        testWindow()
//        testMap()
//        testFlatMap()
//        testConcatMap()
//        testGroupBy()
        
        self.present(FilteringVC(), animated: true, completion: nil)
    }
    
    func testGroupBy(){

//        groupBy 操作符将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。
//        也就是说该操作符会将元素通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。

        Observable<Int>.of(1,2,3,4,5,6,7,8,9)
            .groupBy(keySelector: { (element) -> String in
                return element % 2 == 0 ? "偶数" : "基数"
            })
            .subscribe { (event) in
                switch event{
                case .next(let group):
                    group.asObservable()
                        .subscribe({ (event) in
                        print("event==\(event): \n key = \(group.key)")
                    })
                        .disposed(by:self.disposedB)
                case .completed:
                    print("完成")
                case .error(let myError):
                    print(myError)
                }
                
        }
         .disposed(by:disposedB)
        
        
    }
    
    func testConcatMap(){
        
        //concatMap 与 flatMap 的唯一区别是:当前一个 Observable 元素发送完毕后,后一个Observable 才可以开始发出元素。或者说等待前一个 Observable 产生完成事件后,才对后一个 Observable 进行订阅。
        let subject1 = BehaviorSubject(value: "A")
        let subject2 = BehaviorSubject(value: "1")
        let variable = Variable(subject1) //这里装进去1
        variable.asObservable()
            .concatMap { $0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
        
        subject1.onNext("B")
        variable.value = subject2 //装进去2
        subject2.onNext("2")
        subject1.onNext("C")
        
        /**
         A
         B
         C ==>发现没有打印 1,2的数据,说明了subject1还没有完成
         */
        subject1.onCompleted()
        /**
         A
         B
         C
         2 //为什么没有打印1 因为在储存订阅的时候,发现1没有订阅,结果被2替换了储存,之后订阅,就能打印了
         */
    }
    
    func testFlatMap(){
//        map 在做转换的时候容易出现“升维”的情况。即转变之后,从一个序列变成了一个序列的序列。
//        而 flatMap 操作符会对源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。 然后将这些 Observables 的元素合并之后再发送出来。即又将其 "拍扁"(降维)成一个 Observable 序列。
//        这个操作符是非常有用的。比如当 Observable 的元素本生拥有其他的 Observable 时,我们可以将所有子 Observables 的元素发送出来。
      
        let subject1 = BehaviorSubject(value: "A")
        let subject2 = BehaviorSubject(value: "1")
        let variable = Variable(subject1) //这里装进去1
        variable.asObservable()
            .flatMap { $0 }
            .subscribe(onNext: { print($0) })
            .disposed(by: disposedB)
        
        subject1.onNext("B")
        variable.value = subject2 //装进去2
        subject2.onNext("2")
        subject1.onNext("C")
        //这样12都能打印
   
    }
    
    func testMap(){
    
        //该操作符通过传入一个函数闭包把原来的 Observable 序列转变为一个新的 Observable 序列。
        let subject = PublishSubject<String>()
        subject.map { (str) -> String in
            return str+"hello"
            }
            .subscribe(onNext: { (event) in
                print(event)
            }, onError: nil, onCompleted: {
                print("完成了")
            }) {
                print("销毁了")
            }
            .disposed(by: disposedB)
        
        subject.onNext("Cooci")
        
    }
    
    func testWindow(){
    
//        window 操作符和 buffer 十分相似。不过 buffer 是周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来。
//        同时 buffer要等到元素搜集完毕后,才会发出元素序列。而 window 可以实时发出元素序列。
        
        let subject = PublishSubject<String>()
        subject.window(timeSpan: 2, count: 2, scheduler: MainScheduler.instance)
            .subscribe(onNext: { (event) in
                print(event)
            }, onError: nil, onCompleted: {
                print("完成了")
            }) {
                print("销毁了")
            }
            .disposed(by: disposedB)
        
        subject.onNext("111")
        subject.onNext("222")
        subject.onNext("333")
        
        subject.onNext("aaa")
        subject.onNext("bbb")
        subject.onNext("ccc")
        
    }
        
        
    
    func testBuffer(){
        //buffer 方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。
        //该方法简单来说就是缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来。
        
        let subject = PublishSubject<String>()
        subject.buffer(timeSpan: 2, count: 2, scheduler: MainScheduler.instance)
            .subscribe(onNext: { (event) in
                print(event)
            }, onError: nil, onCompleted: {
                print("完成了")
            }) {
                print("销毁了")
        }
        .disposed(by: disposedB)
        subject.onNext("111")
        subject.onNext("222")
        subject.onNext("333")

        subject.onNext("aaa")
        subject.onNext("bbb")
        subject.onNext("ccc")
        
        //这里每两秒打印一个事件
        //["111", "222"]
//        ["333", "aaa"]
//        ["bbb", "ccc"]
//        [] 当所有事件完毕,不会有储存事件,就会打印空
    }
    
}

感谢 @蘑菇De大灰狼 点出博客存在的纰漏,同时欢迎大家点出,谢谢

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容