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方法里。先别着急,这个过程要比我们想象的复杂一点,我们不能直接订阅isAuthorized的onNext并处理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的转换,是在订阅的时候,根据当前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>>,用序列图来表示是这样的:

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

Observable.of(1, 2, 3).scan(0) {
        accumulatedValue, value in
         accumulatedValue + value
    }.subscribe(onNext: {
        print($0)
    }).addDisposableTo(bag)
输出为 1、3、6.但是,就想上面图中展示的那样,和toArray不同的是,scan在Observable每次有事件的时候都会执行.
转换事件类型的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



