iOS开发进阶 - RxSwift之Observable

来自网络

RxSwift-Reactive Programming with Swift (Swift4.0)

Observables

ObservablesRx的核心,本节将花点时间学习如何创建和使用Observables。在RxSwift中,ObservablesObservables sequencesequence代表相同的意思,RxSwift的世界里,任何事物都是序列observable也是序列,它可以产生事件,事件可以包含值。

Observables三种状态和生命周期

Observables有三种状态分别是nexterrorcompleted。下面使用圆珠图(marble diagram)理解Observables的生命周期。

图片来自RxSwift

上图中从左到右的箭头代表时间,线上的圆珠代表序列事件元素。随着时间的推移线上的元素会被依次发射。observable发射元素产生next事件。

另一张圆珠图,它存在一个结束线。

来自RxSwift

observable发射三个tap事件,当结束时会发个completed事件作为序列的结束标志。例如:tap所在的界面销毁。在observable结束后不再发送任何事件,这种结束方式属于正常终止。

另外,存在一种非正常方式结束序列,如出现错误时,如下面这张图。


来自RxSwift

当错误发送时,observable发射error事件此时序列终止不再发射任何事件。

回顾一下上面三张图:

随着时间推移序列会根据元素依次发送next事件,两种情况导致序列结束,第一,发生错误发射error事件序列终止,第二,发射completed事件序列终止。序列一旦终止就不会再发射任何事件。

Swift中,事件是枚举类型的结构如下:

/// Represents a sequence event.
///
/// Sequence grammar: 
/// **next\* (error | completed)**
public enum Event<Element> {
    /// Next element is produced. ①
    case next(Element)

    /// Sequence terminated with an error. ②
    case error(Swift.Error)

    /// Sequence completed successfully. ③
    case completed
}
  • ① : next携带一个泛型Element
  • ②:error携带一个Swift.Error实例对象。
  • ③:completed表示序列结束不携带值。

创建Observables

了解了Observables概念接下学习如何创建和使用Observables

RxSwift提供多种方式创建Observables。例如:of, just, from, empty, neverrange等。

just: 创建单个事件的序列。of: 创建多个事件的序列。from: 通过数组创建多个事件的序列。empty创建一个空的序列,只发射completed事件。never创建一个不发射事件也不会结束的序列。range(start, count):创建包含多个事件的序列。

// 1. 创建Observables
example(of: "just of from") {
    // 1
    let one = 1
    let two = 2
    let three = 3
    // 2
    let observable1 = Observable.just(one)
    // 3 
    let observable2 = Observable.of(one, two, three)
    let observable3 = Observable.of([one, two, three]) // [Int]
    // 4 
    let observable4 = Observable.from([one, two, three])
    let observable5 = Observable<Void>.empty()
    let observable6 = Observable<Any>.never()
    let observable7 = Observable.range(start: 1, count: 5)
}
  1. 定义三个常量。
  2. 使用just创建只有一个元素的序列,此时序列类型为Observable<Int>
  3. 使用of创建序列,注意Observable2Observable<Int>,而observable3Observable<[Int]>类型 。
  4. 使用from创建序列,此时接收的参数是数组类型。注意:与of的区别。

除了前面的创建方式还可以使用create创建序列。

// Create方法,内部有一个observer
example(of: "Create") {
   // 1
    let disposeBag = DisposeBag()
    // 2 
    Observable<String>.create { observer in
       
        observer.onNext("1")
        observer.onCompleted()
        observer.onNext("2")
        // 3
        return Disposables.create()
    }
    // 4
    .subscribe(
               onNext: {print($0)},
               onError: {print($0)},
               onCompleted: {print("Completed")},
               onDisposed: {print("Disposed")}
    )
    // 5
    .disposed(by: disposeBag)
}
  1. 创建一个DisposeBag对象,用于管理序列
  2. create方法参数是一个逃逸闭包参数为AnyObserver返回值Disposable类型。AnyObserver是通用类型用来将值添加到序列中,在将来发射给订阅者。
  3. 返回disposable代表订阅,Disposables.create()创建了一个空的disposable
  4. 通过subscribe订阅,运行结果你会发现没有输出2,因为在onNext("2")之前,已经发送completed事件序列终止。
  5. 添加到bag中。

订阅序列

订阅序列使用.subscribe方法。直接看示例代码:

// 订阅
example(of: "subscrible") {
    let one = 1
    let two = 2
    let three = 3
    // 1
    let observable = Observable.from([one ,two, three])
    // 2 第一种
    observable.subscribe { event in
        print(event)  // 输出事件
        if let element = event.element {
            print(element)
        }
    }
     // 3 另一种方式
   observable.subscribe(onNext: { (element) in
        print(element)
    }, onError: { (error) in
        print(error)
    }, onCompleted: {
        print("completed")
    }, onDisposed: {
        print("disposed")
    })
}
  1. 创建有多个元素的序列。
  2. 使用func subscribe(_ on: @escaping (Event<Int>) -> Void) -> Disposable方法订阅序列,逃逸闭包参数是Int类型的事件。方法返回值是DisposableDisposable稍后会学到。闭包中参数是事件,通过事件的可选值element参数获取值。
  3. 另一个方法相对方便,直接可以获取到事件的值。注意:onErroronCompletedonDisposed是可选的。

清除和终止

Observable为被订阅时,不会发射任何事件,当出现错误或结束时才会终止。不过,也可以通过清除订阅来终止序列。

每一个订阅者都存在一个dispose方法,当调用该方法时会清除订阅者。示例代码:

// dispose 用于回收,防止内存泄露
example(of: "dispose") {
    let observable = Observable.of("A", "B", "C")
    let subscription = observable.subscribe {event in
        print(event)
    }
    subscription.dispose()
}

example(of: "DisposeBag") {
    let disposeBag = DisposeBag()
    Observable.of("A", "B", "C")
        .subscribe {
            print($0)
    }
    .disposed(by: disposeBag)
}
  • DisposeBag清除包,通过调用dispose方法,取消订阅并且释放内部资源。

三种特殊的Observable

  • Single:不同于Observable它只会发送nexterror事件。Observable通过调用asSingle方法可以转换成Single
    通常用于网络下载或者读取磁盘数据。
example(of: "Single") {
    // 1
    let disposeBag = DisposeBag()

    // 2
    enum FileError: Error {
        case  fileNotFound, unreadable, encodingFailed
    }
    // 3
    func loadText(from name: String) -> Single<String> {
        // 4
        return Single.create { single in
            let disposable = Disposables.create()

            guard let path = Bundle.main.path(forResource: name, ofType: "txt") else {
                single(.error(FileError.fileNotFound))
                return disposable
            }

            guard let data = FileManager.default.contents(atPath: path) else {
                single(.error(FileError.unreadable))
                return disposable
            }
            guard let content = String(data: data, encoding: .utf8) else {
                single(.error(FileError.encodingFailed))
                return disposable
            }
            single(.success(content))
            return disposable
        }
    }

    loadText(from: "Copyright")
        .subscribe {
            switch $0 {
            case .success(let str):
                print(str)
            case .error(let error):
                print(error)
            }
    }
    .disposed(by: disposeBag)
}
  • Completable:只会发送completederror事件。只关心任务是否完成不关心返回值,类似Observable<Void>
  • Maybe: 介于CompletableSingle之间,只会发送一个元素。

本节是对RxSwiftObservable概念和使用的初步学习,循序渐进逐步深入学习深层次内容。

小结

  • Observables是什么?生命周期?
  • Observables 创建方法有哪些?
  • 如何订阅Observable?
  • DisposeBag是什么?它的作用是什么?

参考

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

推荐阅读更多精彩内容