RXSwift ObservableCollection 与 CombineLatest

Posted

技术标签:

【中文标题】RXSwift ObservableCollection 与 CombineLatest【英文标题】:RXSwift ObservableCollection with CombineLatest 【发布时间】:2020-09-22 15:46:55 【问题描述】:

我正在尝试实现这样的东西,

    let api1 = Observable.of(["documents"])    //Replace with observable to download docs
    let api2 = Observable.of(["applications"]) //Replace with observable to download apps
    let api3 = Observable.of(["videos"])       //Replace with observable to download videos

    Observable.combineLatest(api1, api2, api3)(docs, apps, videos) in
        return (docs, apps, videos)
    .skipWhile (docs, apps, videos) in
        return docs.count == 0 && apps.count == 0 && videos.count == 0
    .subscribe(onNext:(docs, apps, videos) in

    )
    .disposed(by:disposeBag)

就我而言,我正在尝试动态创建可观察对象并将其添加到这样的数组中,

private var discoverObservables = [Observable<Any>]()


func loadDiscoverFeeds()
      
        self.feeds.forEach(
            feed in
            switch feed.feedType
            case "a":
                let observable = self.aObservable(url: feed.feedURL ?? "")
                self.discoverObservables.append(observable)
                break
            case "b":
                let observable = self.bObservable(url: feed.feedURL ?? "")
                self.discoverObservables.append(observable)
                break
            case "c":
                let observable = self.cObservable(url: feed.feedURL ?? "")
                self.discoverObservables.append(observable)
                break
            case "d" :
                let observable = self.dObservable(url: feed.feedURL ?? "")
                self.discoverObservables.append(observable)
                break
            default:
                break
            
            
        )


    private func aObservable(url : String) -> Observable<A?>
            return APIManager.shared.getA(url: url)
        

    private func bObservable(url : String) -> Observable<B?>
            return APIManager.shared.getB(url: url)
        


    private func cObservable(url : String) -> Observable<C?>
            return APIManager.shared.getC(url: url)
        

但这不起作用,因为 discoverObservables 数组期待类型 Observable&lt;Any&gt; 的值,我正在尝试添加 Observable

我怎样才能正确地做到这一点,我想在我开始处理数据之前确保所有的 observables 都返回数据。

编辑 我正在尝试从不同来源加载数据,然后再将其添加到视图中,基本上,我有一个 collectionview,每个部分都从不同的 API 加载数据,我正在尝试从所有来源获取所有必需的数据,然后再将其添加到集合中查看。

【问题讨论】:

您显示了aObservable(url:) 的声明,但bObservable(url:)cObserrvable(url:) 的声明是什么?他们返回什么? 另外,Observables 不应该是vars。你在这里做的是根本错误的事情。 @DanielT。我添加了一些细节,希望对您有所帮助。 我已经更新了我的答案。 【参考方案1】:

将相同的协议添加到 A、B 和 C。

protocol YourProtocol ...

class A: YourProtocol ...
class B: YourProtocol ...
class C: YourProtocol ...

然后你可以制作:

private var discoverObservables = [Observable<YourProtocol>]() 

【讨论】:

【参考方案2】:

第一个代码块似乎在做这项工作,但有一个例外,条件检查所有(文档、应用程序、视频)是否为空,也许您想使用 || 而不是 &amp;&amp;

至于第二个带有数组的代码块,我做了一些可以帮助的事情。

    struct A 
    
    let observable1 = Observable.just(A())
    let observable2 = Observable.just(A())
    let observable3 = Observable.just(A())

    let observables: [Observable<A>] = [observable1, observable2, observable3]
    
    Observable.combineLatest(observables).skipWhile  (streams) -> Bool in
        streams.forEach 
            if $0.count == 0  return true 
        
        return false
    .subscribe(...

此订阅将产生Observable&lt;[A]&gt;

【讨论】:

【参考方案3】:

我将从您的问题中专门解决这个问题:“我想确保在开始处理数据之前所有可观察对象都返回数据。”

严格来说,您可能不需要Any 结构。更好的是协议或枚举。我看到其他答案已经解决了协议的想法,所以我将使用枚举的想法:

enum EndpointResponse 
    case a(A?)
    case b(B?)
    // etc...


let responses = Observable.zip(
    feeds.map  (feed) -> Observable<EndpointResponse> in
        switch feed.feedType 
        case "a":
            return aObservable(url: feed.feedURL ?? "").map  EndpointResponse.a($0) 
        case "b":
            return bObservable(url: feed.feedURL ?? "").map  EndpointResponse.b($0) 
        default:
            fatalError()
        
    
)

上面的responses observable 将包含所有响应的数组,一旦它们具有所有发出的值。换句话说,zip 运算符将收集来自所有网络调用的所有响应,并发出一个包含所有响应的数组。

我之前的回答:

问题中确实没有太多信息可以继续,但类似这样的内容回答了您提出的关于将Observable&lt;X&gt; 转换为Observable&lt;Any&gt; 的直接问题...

let discoverObservables = Observable.zip(
    feeds.map  (feed) -> Observable<Any> in
        switch feed.feedType 
        case "a":
            return aObservable(url: feed.feedURL ?? "").map  $0 as Any 
        case "b":
            return bObservable(url: feed.feedURL ?? "").map  $0 as Any 
        case "c":
            return cObservable(url: feed.feedURL ?? "").map  $0 as Any 
        case "d":
            return dObservable(url: feed.feedURL ?? "").map  $0 as Any 
        default:
            break
        
    
)

【讨论】:

以上是关于RXSwift ObservableCollection 与 CombineLatest的主要内容,如果未能解决你的问题,请参考以下文章

RxSwift

RXSwift的一些基本交互(OC,Swift,RXSwift对比)

如何正确安装“RxSwift”模块?

RxSwift + 用户默认值

给 iOS 开发者的 RxSwift

RxSwift + Moya + ObjectMapper