RxSwift文档(中文翻译中)

接上回书:

关于操作符"shareReplay"

假如你需要多个观察者(observer)共享同一个订阅(subscription),那么你就要确定两件事情

  • 如果一个序列被一个新的订阅者订阅了,那该如何处理之前已经被接收的元素呢?(重播最后一个元素,还是所有的元素,亦或者是最后n个)
  • 如何决定何时触发被共享的订阅(subscripiton)呢?
    通常情况下你会使用到shareReplay:
let counter = myInterval(0.1)
    .shareReplay(1)

print("Started ----")

let subscription1 = counter
    .subscribe(onNext: { n in
        print("First \(n)")
    })
let subscription2 = counter
    .subscribe(onNext: { n in
        print("Second \(n)")
    })

Thread.sleep(forTimeInterval: 0.5)

subscription1.dispose()

Thread.sleep(forTimeInterval: 0.5)

subscription2.dispose()

print("Ended ----")
打印结果:
//Started ----
Subscribed
First 0
Second 0
First 1
Second 1
First 2
Second 2
First 3
Second 3
First 4
Second 4
First 5
Second 5
Second 6
Second 7
Second 8
Second 9
Disposed
Ended ----

shareReplay,多个订阅者共享结果,就像您看到的,使用了该操作符的序列,在有多个订阅者订阅的时候,并不会调用多次之前构造myInterval时候闭包里的代码(结果只打印了一次subscribed,Disposed事件).为了更好地理解shareReplay,参照这篇文章给出的例子:

let sequenceOfInts = PublishSubject()
let a = sequenceOfInts.map{ i -> Int in
    print("MAP---\(i)")
    return i * 2
    }.shareReplay(1)
let b = a.subscribe(onNext:{
    print("--1--\($0)")
})
sequenceOfInts.on(.next(1))
sequenceOfInts.on(.next(2))
let c = a.subscribe (onNext: {
    print("--2--\($0)")
})
sequenceOfInts.on(.next(3))
sequenceOfInts.on(.next(4))
let d = a.subscribe (onNext:{
    print("--3--\($0)")
})
sequenceOfInts.on(.completed)

快去看看使用和不使用shareReplay打印的结果吧!
注: shareReplay的参数代表了共享最后几次结果.想象一下该操作符的实际运用场景,最直观的就是网络请求,如果多个订阅者订阅了某个网络请求,我们没必要去重复的请求网络,这时候就有了shareReplay的用武之地了!
下面是HTTP请求在Rx中的范例,这其实跟interval操作符很像:

extension Reactive where Base: URLSession {
    public func response(_ request: URLRequest) -> Observable<(Data, HTTPURLResponse)> {
        return Observable.create { observer in
            let task = self.dataTaskWithRequest(request) { (data, response, error) in
                guard let response = response, let data = data else {
                    observer.on(.error(error ?? RxCocoaURLError.Unknown))
                    return
                }

                guard let httpResponse = response as? HTTPURLResponse else {
                    observer.on(.error(RxCocoaURLError.nonHTTPResponse(response: response)))
                    return
                }

                observer.on(.next(data, httpResponse))
                observer.on(.completed)
            }

            task.resume()

            return Disposables.create {
                task.cancel()
            }
        }
    }
}

操作符(Operators)

在RxSwift的世界里,有众多的操作符可供选择,你可以在这里找到所有的操作符使用说明.你也可以在RxSwift Demo的PlayGround里看到几乎所有使用到的操作符的演示,快去试试吧!

自定义操作符(Custom Operators)

让我们来动手实现一个自己的map操作符myMap吧!

extension ObservableType {
    func myMap(transform: @escaping (E) -> R) -> Observable {
        return Observable.create { observer in
            let subscription = self.subscribe { e in
                    switch e {
                    case .next(let value):
                        let result = transform(value)
                        observer.on(.next(result))
                    case .error(let error):
                        observer.on(.error(error))
                    case .completed:
                        observer.on(.completed)
                    }
                }

            return subscription
        }
    }
}

好吧,很清爽,一个转换函数(transform)作为参数,返回一个Observable,咦,等等,好像这个家伙跟Swift数组的map方法很像啊,好像做的事情一毛一样;数组的元素被转换,得到的是另一个数组,Observable的value值被转换,得到另外的一个Observable.你完全可以把Observable想象成Swfit数组嘛,他们都是容器.
现在你可以使用自己的myMap方法了:

let subscription = myInterval(0.1)
    .myMap { e in
        return "This is simply \(e)"
    }
    .subscribe(onNext: { n in
        print(n)
    })
    打印结果:
    //Subscribed
This is simply 0
This is simply 1
This is simply 2
This is simply 3
This is simply 4
This is simply 5
This is simply 6
This is simply 7
This is simply 8
...

错误处理

Observable中的异步处理错误机制
如果一个序列以错误终止,那么所有依赖序列同样会以错误终止,参照短路逻辑.
你可以用catch操作符捕捉Observable序列的error.你也可以使用Retry操作符把error信号过滤掉.

RxSwift文档(中文翻译中)_第1张图片
B9D594F9-91C2-4F3E-8FDF-72861181C856.png

调试编译器的错误

当你书写优雅的RxSwift或者RxCocoa代码的时候,你很大程度上会依赖编译器来推断Observables的类型,这也是Swift真正优秀的地方,但是,这有时也会带来一些苦恼.

images = word
    .filter { $0.containsString("important") }
    .flatMap { word in
        return self.api.loadFlickrFeed("karate")
            .catchError { error in
                return just(JSON(1))
            }
      }

如果编译器报出错误(未知的类型),那么我建议你首先在闭包里注明闭包的返回值.例如:

images = word
    .filter { s -> Bool in s.containsString("important") }
    .flatMap { word -> Observable in
        return self.api.loadFlickrFeed("karate")
            .catchError { error -> Observable in
                return just(JSON(1))
            }
      }

如果还不行,那干脆这样:

images = word
    .filter { (s: String) -> Bool in s.containsString("important") }
    .flatMap { (word: String) -> Observable in
        return self.api.loadFlickrFeed("karate")
            .catchError { (error: Error) -> Observable in
                return just(JSON(1))
            }
      }

注: 其实笔者还是建议初学者写出完整的闭包语法,这既有助于理解代码,闭包类型又一目了然.但是,显然这样还有失优雅.

代码调试

你可以单独使用调试器,但大多时候使用debug操作符是更高效的,你可以这样做:

let subscription = myInterval(0.1)
    .debug("my probe")
    .map { e in
        return "This is simply \(e)"
    }
    .subscribe(onNext: { n in
        print(n)
    })

Thread.sleepForTimeInterval(0.5)

subscription.dispose()
打印结果:
//
[my probe] subscribed
Subscribed
[my probe] -> Event next(Box(0))
This is simply 0
[my probe] -> Event next(Box(1))
This is simply 1
[my probe] -> Event next(Box(2))
This is simply 2
[my probe] -> Event next(Box(3))
This is simply 3
[my probe] -> Event next(Box(4))
This is simply 4
[my probe] dispose
Disposed

当然,你同样可以很轻松的自定义你自己的debug操作符:

extension ObservableType {
    public func myDebug(identifier: String) -> Observable {
        return Observable.create { observer in
            print("subscribed \(identifier)")
            let subscription = self.subscribe { e in
                print("event \(identifier)  \(e)")
                switch e {
                case .next(let value):
                    observer.on(.next(value))

                case .error(let error):
                    observer.on(.error(error))

                case .completed:
                    observer.on(.completed)
                }
            }
            return Disposables.create {
                   print("disposing \(identifier)")
                   subscription.dispose()
            }
        }
    }
 }

后话: 笔者终于在大年三十晚上听着掏粪男神们不知道真唱假唱的<<美丽中国年>>中完成了RxSwift文档翻译工作的中篇,不过好像气氛有点不对劲呢...只有我一个人在怀疑这是不是在过年吗?
未完待续...

你可能感兴趣的:(RxSwift文档(中文翻译中))