美文网首页RxSwift
RxSwift_操作符_share(replay:scope:)

RxSwift_操作符_share(replay:scope:)

作者: MR_詹 | 来源:发表于2021-03-12 11:05 被阅读0次

    share(replay:scope:) 作用:
    解决有多个订阅者的情况下,避免事件转换操作符(比如:map、flatMap、flatMapLatest等等)被多次执行的问题

    #普通的可观察序列
    let seq = PublishSubject<Int>()
    let ob = seq.map { (i) -> Int in
        print("map 被调用 :---\(i)")
        return i * 2
    }
    
    let _ = ob.subscribe(onNext: { (num) in
        print("--第一次订阅--\(num)")
    }, onError: nil, onCompleted: nil, onDisposed: nil)
    
    
    let _ = ob.subscribe(onNext: { (num) in
        print("--第二次订阅--\(num)")
    }, onError: nil, onCompleted: nil, onDisposed: nil)
    
    seq.onNext(1)
    
    /// 打印结果:
    /// map 被调用 :---1
    /// --第一次订阅--2
    /// map 被调用 :---1
    /// --第二次订阅--2
    
    #带share 
    
    let seq = PublishSubject<Int>()
    let ob = seq.map { (i) -> Int in
        print("map 被调用 :---\(i)")
        return i * 2
    }
    /// replay:缓存的事件个数
    /// scope:subject是否独立(使用说明请看下方)
    .share(replay: 0, scope: .forever)
    
    let _ = ob.subscribe(onNext: { (num) in
        print("--第一次订阅--\(num)")
    }, onError: nil, onCompleted: nil, onDisposed: nil)
    
    
    let _ = ob.subscribe(onNext: { (num) in
        print("--第二次订阅--\(num)")
    }, onError: nil, onCompleted: nil, onDisposed: nil)
    
    seq.onNext(1)
    
    /// 打印结果:
    /// map 被调用 :---1
    /// --第一次订阅--2
    /// --第二次订阅--2
    

    总结
    从上面例子可以知道:
    发送一次onNext事件,就对应一个Observable,而所有的观察者都只对应这个Observable,Observable共享给所有的观察者

    share(replay:scope:) 操作符使得观察者共享Observable,并且缓存最新的n个元素,将这些元素直接发送给新的观察者

    看了上面的两个例子,貌似已经懂得share操作符的基本使用,嘻嘻嘻嘻
    请继续看下面的例子

    # 代码一:没有使用share
    
    let net = Observable<String>.create { (ob) -> Disposable in
        print("我开始网络请求了")
        ob.onNext("请求结果")
        ob.onCompleted()
        return Disposables.create {
            print("销毁了")
        }
    }
    
    net.subscribe(onNext:{
        print("第一次订阅:\($0)",Thread.current)
    }).disposed(by: bag)
    
    net.subscribe(onNext:{
      print("第二次订阅:\($0)",Thread.current)
    }).disposed(by: bag)
    
    
    /// 打印结果:
    /// 我开始网络请求了
    /// 第一次订阅:请求结果 <NSThread: 0x600002ce0a40>{number = 1, name = main}
    /// 销毁了
    /// 我开始网络请求了
    /// 第二次订阅:请求结果 <NSThread: 0x600002ce0a40>{number = 1, name = main}
    /// 销毁了
    
    # 代码二:share(replay: 0, scope: .whileConnected)
    
    let net = Observable<String>.create { (ob) -> Disposable in
        print("我开始网络请求了")
        ob.onNext("请求结果")
        ob.onCompleted()
        return Disposables.create {
            print("销毁了")
        }
    }.share(replay: 0, scope: .whileConnected)
    
    
    net.subscribe(onNext:{
        print("第一次订阅:\($0)",Thread.current)
    }).disposed(by: bag)
    
    net.subscribe(onNext:{
      print("第二次订阅:\($0)",Thread.current)
    }).disposed(by: bag)
    
    /// 打印结果:
    /// 我开始网络请求了
    /// 第一次订阅:请求结果 <NSThread: 0x600001b1c900>{number = 1, name = main}
    /// 销毁了
    /// 我开始网络请求了
    /// 第二次订阅:请求结果 <NSThread: 0x600001b1c900>{number = 1, name = main}
    /// 销毁了
    

    首先通过上面两端代码的打印结果,发现share貌似也不起什么作用,其实不然。讲这个之前,请先看RxSwift中对share方法中对scope参数的注释

    * `.whileConnected`
    // Each connection will have it's own subject instance to store replay events.
    // Connections will be isolated from each another.
    // source.multicast(makeSubject: { Replay.create(bufferSize: replay) }).refCount()
    
    * `.forever`
    // One subject will store replay events for all connections to source.
    // Connections won't be isolated from each another.
    // source.multicast(Replay.create(bufferSize: replay)).refCount()
    

    scope是一个枚举值,包括whileConnected、forever
    官方文档注释的大概意思是:
    whileConnected:每个connection 都有单独的一个Subject存储事件Event
    forever:用一个Subject存储所有的connections的事件Event

    为了理解这个,我们将“代码二”中的.whileConnected 修改为 .forever
    看看结果有什么不一样的

    #代码三
    
    let net = Observable<String>.create { (ob) -> Disposable in
        print("我开始网络请求了")
        ob.onNext("请求结果")
        ob.onCompleted()
        return Disposables.create {
            print("销毁了")
        }
    }.share(replay: 0, scope: .forever)
    
    
    net.subscribe(onNext:{
        print("第一次订阅:\($0)",Thread.current)
    })
    .disposed(by: bag)
    
    net.subscribe(onNext:{
      print("第二次订阅:\($0)",Thread.current)
    }).disposed(by: bag)
    
    /// 打印结果:
    /// 我开始网络请求了
    /// 第一次订阅:请求结果 <NSThread: 0x600003390480>{number = 1, name = main}
    /// 销毁了
    

    发现打印结果,少了订阅2。这是为什么了?
    根据注释,.forever 是使用一个Subject存储所有的连接的Event,
    在第一次订阅的时候,触发Observable的构建函数,但是在发送事件完之后就发送了complete,既然已经发送了complete那么代表存储的Subject已经结束了,所以第二次订阅并没有打印

    PS: 这种情况如果想要实现多次订阅,然后只执行一次网络请求的,可以参考这个文章的解决方案:使用功能操作符. publish

    项目使用

    项目比较常用的可能就是封装网络请求的Observable中,在Observable中添加share(replay:scope:)操作符,目的是为了在多个位置订阅,避免发一次的Event,而重复多个请求

    相关文章

      网友评论

        本文标题:RxSwift_操作符_share(replay:scope:)

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