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<Any>
的值,我正在尝试添加 Observable
我怎样才能正确地做到这一点,我想在我开始处理数据之前确保所有的 observables 都返回数据。
编辑 我正在尝试从不同来源加载数据,然后再将其添加到视图中,基本上,我有一个 collectionview,每个部分都从不同的 API 加载数据,我正在尝试从所有来源获取所有必需的数据,然后再将其添加到集合中查看。
【问题讨论】:
您显示了aObservable(url:)
的声明,但bObservable(url:)
和cObserrvable(url:)
的声明是什么?他们返回什么?
另外,Observables 不应该是var
s。你在这里做的是根本错误的事情。
@DanielT。我添加了一些细节,希望对您有所帮助。
我已经更新了我的答案。
【参考方案1】:
将相同的协议添加到 A、B 和 C。
protocol YourProtocol ...
class A: YourProtocol ...
class B: YourProtocol ...
class C: YourProtocol ...
然后你可以制作:
private var discoverObservables = [Observable<YourProtocol>]()
【讨论】:
【参考方案2】:第一个代码块似乎在做这项工作,但有一个例外,条件检查所有(文档、应用程序、视频)是否为空,也许您想使用 ||
而不是 &&
。
至于第二个带有数组的代码块,我做了一些可以帮助的事情。
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<[A]>
。
【讨论】:
【参考方案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<X>
转换为Observable<Any>
的直接问题...
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的主要内容,如果未能解决你的问题,请参考以下文章