首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >链式网络请求RXSwift

链式网络请求RXSwift
EN

Stack Overflow用户
提问于 2021-03-22 22:25:16
回答 1查看 228关注 0票数 2

嘿,我在HackingWithSwift教程中学到了如何使用Combine发出链式网络请求(参见下面的代码)。现在我将使用RXSwift构建相同的逻辑,但我不知道如何像Combine中那样获取/订阅以获得最终结果。

合并:

代码语言:javascript
运行
复制
//Combine code
func fetch<T: Decodable>(_ url: URL, defaultValue: T) -> AnyPublisher<T, Never> {
       let decoder = JSONDecoder()
       decoder.dateDecodingStrategy = .iso8601

       return URLSession.shared.dataTaskPublisher(for: url)
           .retry(1)
           .map(\.data)
           .decode(type: T.self, decoder: decoder)
           .replaceError(with: defaultValue)
           .receive(on: DispatchQueue.main)
           .eraseToAnyPublisher()
   }

//call fetch method and get the end result 
fetch(url, defaultValue: [URL]())
        .flatMap { urls in
           urls.publisher.flatMap { url in
              fetch(url, defaultValue: [NewsItem]())
           }
        }
        .collect()
        .sink { values in
            let allItems = values.joined()
            items = allItems.sorted { $0.id > $1.id }
        }
        .store(in: &requests)



//RXSwift code
func fetchWithRX<T: Decodable>(_ url: URL, defaultValue: T) -> Observable<T> {
       let decoder        = JSONDecoder()
       decoder.dateDecodingStrategy = .iso8601
       let request        = URLRequest(url: url)
       
       return URLSession.shared.rx.response(request: request)
           .retry(1)
           .map(\.data)
           .decode(type: T.self, decoder: decoder)
           .debug()
           .catchAndReturn(defaultValue)
           .observe(on: MainScheduler.instance)
   }


//call fetch2 method 
Now I want to subscribe to the values like in the first fetch method with flatMap..collect..sink etc.

fetchWithRX(url, defaultValue:  [URL]()) 
EN

回答 1

Stack Overflow用户

发布于 2021-03-23 09:14:20

我会这样写这个类比:

代码语言:javascript
运行
复制
fetchWithRX(url, defaultValue: [URL]())
    .flatMap { urls in
        Observable.zip(urls.map { fetchWithRX($0, defaultValue: [NewsItem]()) })
    }
    .map { $0.flatMap { $0 }.sorted { $0.id > $1.id } }
    .subscribe(onNext: { values in
        items = values
    })
    .disposed(by: requests)

这样,我将把所有的逻辑转移到一个map闭包中,这个闭包可以转移到一个用于测试的函数中。尽量减少flatMapsubscribe中的代码量,以提高代码的可测试性。

或者你可以这样写:

代码语言:javascript
运行
复制
fetchWithRX(url, defaultValue: [URL]())
    .flatMap { urls in
        Observable.zip(urls.map { fetchWithRX($0, defaultValue: [NewsItem]()) })
    }
    .subscribe(onNext: { values in
        let allItems = values.joined()
        items = allItems.sorted { $0.id > $1.id }
    })
    .disposed(by: requests)

您可以在本文中了解有关组合可观察对象的更多信息:Recipes for Combining Observables in RxSwift

URLSession还有一个操作符data(request:),它只会发出数据,因此您不必映射即可转储结果对象。如下所示:

代码语言:javascript
运行
复制
func fetchWithRX<T: Decodable>(_ url: URL, defaultValue: T) -> Observable<T> {
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .iso8601
    return URLSession.shared.rx.data(request: URLRequest(url: url))
        .retry(1)
        .decode(type: T.self, decoder: decoder)
        .catchAndReturn(defaultValue)
        .observe(on: MainScheduler.instance)
}

我突然想到,您可能正在寻找原始组合代码的直接推论……上面的示例将具有相同的最终输出,但它们的工作方式略有不同……

这是一个直接的翻译:

代码语言:javascript
运行
复制
fetchWithRX(url, defaultValue: [URL]())
    .flatMap { urls in
        // Observable.from(urls) works like urls.publisher 
        Observable.from(urls).flatMap { url in
            fetchWithRX(url, defaultValue: [NewsItem]())
        }
    }
    .toArray() // works like collect(). However, toArray() returns a Single rather than a generic Observable.
    .subscribe(onSuccess: { values in
        let allItems = values.joined()
        items = allItems.sorted { $0.id > $1.id }
    })
    .disposed(by: requests)

不同之处在于,其他示例保留了新闻条目的顺序,而这个示例则不是,因为您无论如何都是在收集和排序,所以最终的输出是相同的。只有在观察输出之前没有使用collect()/toArray()时,才会看到不同之处。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66747996

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档