RxSwift-step(二)

12-理解重复订阅Observable的行为

share() - 不要反复订阅同一个Observable

let numbers = Observable.of(1, 2, 3, 4, 5)

_ = numbers.subscribe(onNext: { print($0) })
_ = numbers.subscribe(onNext: { print($0) })

假设,我们希望这两次订阅实际上使用的是同一个Observable,但执行一下就会在控制台看到,打印了两次1 2 3 4 5,也就是说每次订阅,都会产生一个新的Observable对象,多次订阅的默认行为,并不是共享同一个序列上的事件。

为了在多次订阅的时候共享事件,我们可以使用share operator,为了观察这个效果,我们把numbers的定义改成这样:

let numbers = Observable.of(1, 2, 3, 4, 5).share()

scan operator

_ = selectedPhotos.scan([]) {
    (photos: [UIImage], newPhoto: UIImage) in
        var newPhotos = photos

        if let index = newPhotos.index(where: { newPhoto == $0 }) {
            newPhotos.remove(at: index)
        }
        else {
            newPhotos.append(newPhoto)
        }

        return newPhotos
    }.subscribe(onNext: { (photos: [UIImage]) in
        self.images.value = photos
    }, onDisposed: {
        print("Finished choose photo memos.")
    })

上述的scan作用类似于集合类型中的reduce.

13-更好的处理授权提示

iOS的用户授权动作是异步的.为了能在用户完成授权操作之后继续更新UI,我们得先把授权的结果封装成一个Observable。实际上,这个Observable只可能是下面三种情况:
* 如果用户已授权,事件序列就是:.next(true).completed()
* 如果用户未授权,序列的第一个事件就一定是.next(false)。然后,如果用户拒绝授权,序列中的事件就是:.next(false).completed。否则,就是.next(true).completed

订阅用户的授权结果

订阅的部分,应该写在PhotoCollectionViewController.viewDidLoad方法里。先别着急,这个过程要比我们想象的复杂一点,我们不能直接订阅isAuthorizedonNext并处理true/false的情况,因为单一的事件值并不能反映真实的授权情况。按照之前分析的:

  • 授权成功的序列可能是:.next(true).completed.next(false).next(true).completed
  • 授权失败的序列则是:.next(false).next(false).completed
    因此,我们需要把isAuthorized这个事件序列处理一下,分别处理授权成功和失败的情况。

订阅成功事件

首先来订阅授权成功事件,我们只要忽略掉事件序列中所有的false,并读到第一个true,就可以认为授权成功了。使用“过滤型”operator可以轻松完成这个任务:

override func viewDidLoad() {
    super.viewDidLoad()
    ...
    // PHPhotoLibrary.isAuthorized返回一个Observable<Bool>
    let isAuthorized = PHPhotoLibrary.isAuthorized

    isAuthorized
        .skipWhile { $0 == false }
        .take(1)
        .subscribe(onNext: {
            [weak self] _ in
            // Reload the photo collection view
        })
        .addDisposableTo(bag)
}

可以看到, 上面的代码中, 使用skipWhile忽略了所有false, 并且读取到了之后第一个true.

订阅失败事件

接下来,我们处理拒绝授权的情况。这种情况相比成功简单一些,因为它对应的事件序列只有一种情况:.next(false).next(false).completed。因此,我们只要对事件序列中所有元素去重之后,订阅最后一个.next事件,如果是false,就可以确定是用户拒绝授权了。因此,在订阅成功授权的代码后面,继续添加下面的代码:

override func viewDidLoad() {
    super.viewDidLoad()
    ...

    isAuthorized
        .distinctUntilChanged()
        .takeLast(1)
        .filter{ $0 == false }
        .subscribe(onNext: { [weak self] _ in
            self?.flash(title: "Cannot access your photo library",message: "You can authorize access from the Settings.",
            callback: { [weak self] _ in
                self?.navigationController?.popViewController(animated: true)
            }))

        })
        .addDisposableTo(bag)

}

14-了解常用的transform operators

toArray

toArray,这可以说是最简单的Transform operator。它把Observable<T>中所有的事件值,在订阅的时候,打包成一个Array<T>返回给订阅者.
toArray
有一点要注意的是,toArray的转换,是在订阅的时候,根据当前Observable中的值一次性完成转换的,后续的事件订阅则不会再进行转换:

let numbers = PublishSubject<Int>()

numbers.asObservable()
    .toArray()
    .subscribe(onNext: {
        print($0)
    }).addDisposableTo(bag)


numbers.onNext(1)
numbers.onNext(2)
numbers.onNext(3)

对于这个例子来说,在订阅的时候,使用了toArray,但此时,numbers中没有任何值,toArray变换出来的,就是个空数组。即便之后numbers中发生了事件123,但是,我们订阅的,已经不是numbers,而是numbers在订阅的时候转换成的Observable<Array<Int>>,用序列图来表示是这样的:

toArray立即转换
我们订阅的代码是图中红色的Observable,因此,也就不会打印任何内容了。

scan

scan

Observable.of(1, 2, 3).scan(0) {
        accumulatedValue, value in
         accumulatedValue + value
    }.subscribe(onNext: {
        print($0)
    }).addDisposableTo(bag)

输出为 1、3、6.但是,就想上面图中展示的那样,和toArray不同的是,scanObservable每次有事件的时候都会执行.

转换事件类型的map

Observable.of(1, 2, 3).map {
    value in value * 2
}.subscribe(onNext: {
    print($0)
}).addDisposableTo(bag)

15-为什么RxSwift也需要flatMap

flatMap集合中使用到, 在Optional中也使用到, 到了RxSwift也用到它, 但是在这些不同的领域中, flatMap往往又表示了不同的含义. 在RxSwift中是这么定义flatMap的:

Transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable.

翻译过来就是 将由Observable 发送来的Item转换成一个个Observables, 然后再展开, 将所有Observables的发射序列合并成一个Observable.

把序列中的事件变成新的Observable

来看下RxSwift官方demo中提供的例子:

struct Player {
        var score: Variable<Int>
    }

    let 👦🏻 = Player(score: Variable(80))
    let 👧🏼 = Player(score: Variable(90))

然后创建一个Variable, 然后订阅它

    let player = Variable(👦🏻)

    player.asObservable()
        .flatMap { $0.score.asObservable() } // Change flatMap to flatMapLatest and observe change in printed output
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)

    👦🏻.score.value = 85 // 输出 80  85

👦🏻是Player序列中发生的事件, 通过flatMap我们把它变成了一个Observable<Int>, 这就是flatMap定义的前半句话的含义: Transform the items emitted by an Observable into Observables.

合并所有Observables的发射序列

接下来, 我们把👧🏼加入, 注意下👧🏼添加的位置


    player.value = 👦🏻 // 输出80
    👦🏻.score.value = 85 // 输出85

    player.value = 👧🏼 // 输出90

    👧🏼.value = 95 // 输出95

订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x