美文网首页iOS-swiftiOS Developer
RxSwift文档(中文翻译中)

RxSwift文档(中文翻译中)

作者: 2e919d99a871 | 来源:发表于2017-01-27 20:35 被阅读276次

    接上回书:

    关于操作符"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<Int>()
    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<R>(transform: @escaping (E) -> R) -> Observable<R> {
            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信号过滤掉.

    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<JSON> in
            return self.api.loadFlickrFeed("karate")
                .catchError { error -> Observable<JSON> in
                    return just(JSON(1))
                }
          }
    

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

    images = word
        .filter { (s: String) -> Bool in s.containsString("important") }
        .flatMap { (word: String) -> Observable<JSON> in
            return self.api.loadFlickrFeed("karate")
                .catchError { (error: Error) -> Observable<JSON> 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<Self.E> {
            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文档(中文翻译中)

        本文链接:https://www.haomeiwen.com/subject/zwonbttx.html