Chain requests 和 return 都是 RxSwift 的结果

Chain requests and return both results with RxSwift

我有一个 ContentService 请求一篇文章。该文章回复包含 authorId 属性。

我有一个 ProfileService 允许我通过 userId.

请求用户配置文件

我正在尝试从 ContentService 请求一篇文章,一旦使用 authorId 属性 完成到 ProfileService 的请求链,我就会喜欢 return 包含文章和个人资料信息的 ContentArticleViewModel

我的 ArticleInteractor 看起来像这样 -

final class ArticleInteractor: ArticleInteractorInputProtocol {

    let fetchArticleTrigger = PublishSubject<String>()

    private lazy var disposeBag = DisposeBag()

    weak var output: ArticleInteractorOutputProtocol? {
        didSet {
            configureSubscriptions()
        }
    }

    private func configureSubscriptions() {
        guard let output = output else { return }

        fetchArticleTrigger
            .bind(to: dependencies.contentSvc.fetchContentByIdTrigger)
            .disposed(by: disposeBag)

        dependencies.contentSvc.fetchContentByIdResponse
            .bind(to: output.fetchArticleResponse)
            .disposed(by: disposeBag)
    }
}

很简单 fetchArticleTrigger 开始请求,然后我 binddependencies.contentSvc.fetchContentByIdResponse 上接收响应。

ContentService上的方法是-

    // MARK:- FetchContentById
    // @params: id - String
    // return: PublishSubject<ContentArticle>

        fetchContentByIdTrigger
            .flatMapLatest { [unowned self] in self.client.request(.getContentById(id: [=12=])) }
            .map { (resp: Result<ContentArticle>) in
                guard case .success(let props) = resp else { return ContentArticle() }
                return props
        }
        .bind(to: fetchContentByIdResponse)
        .disposed(by: disposeBag)

我的 ProfileService -

上有一个非常相似的设置
    // MARK:- FetchUserProfileById
    // @params: id - String
    // return: PublishSubject<User>
        fetchUserProfileByIdTrigger
            .flatMapLatest { [unowned self] in self.client.request(.getProfileByUserId(id: [=13=])) }
            .map { (resp: Result<User>) in
                guard case .success(let props) = resp else { return User() }
                return props
        }
        .bind(to: fetchUserProfileByIdResponse)
        .disposed(by: disposeBag)

我想我会为文章创建一个模型,比如 -

struct ContentArticleViewModel {
    var post: ContentArticle
    var user: User
}

我在我的 ArticleInteractor-

中想象类似这个伪代码的东西
    dependencies.contentSvc.fetchContentByIdResponse
        .flatMapLatest { article in
             /* fetch profile using `article.authorId */
        }.map { article, profile in
            return ContentArticleViewModel(post: article, user: profile)
        }
        .bind(to: output.fetchArticleResponse)
        .disposed(by: disposeBag)

但我完全不知道如何最好地处理这个问题。我看过很多关于链接请求的文章,但我很难成功地应用任何东西。

编辑

我目前有一些工作 -

    private func configureSubscriptions() {
        guard let output = output else { return }

        fetchArticleTrigger
            .bind(to: dependencies.contentSvc.fetchContentByIdTrigger)
            .disposed(by: disposeBag)

        dependencies.contentSvc.fetchContentByIdResponse
            .do(onNext: { [unowned self] article in self.dependencies.profileSvc.fetchUserProfileByIdTrigger.onNext(article.creator.userId)})
            .bind(to: fetchArticleResponse)
            .disposed(by: disposeBag)

        let resp = Observable.combineLatest(fetchArticleResponse, dependencies.profileSvc.fetchUserProfileByIdResponse)

        resp
            .map { [unowned self] in self.enrichArticleAuthorProps(article: [=16=], user: ) }
            .bind(to: output.fetchArticleResponse)
            .disposed(by: disposeBag)
    }

    private func enrichArticleAuthorProps(article: ContentArticle, user: User) -> ContentArticle {
        var updatedArticle = article
        updatedArticle.creator = user
        return updatedArticle
    }

不过我不确定这是否正确。

我不知道为什么这么小的工作你有这么多代码。下面是一个示例,它执行您描述的操作(下载文章、下载作者简介并发出两者),代码少得多,甚至 比我通常使用的代码更多。

protocol ContentService {
    func requestArticle(id: String) -> Observable<Article>
    func requestProfile(id: String) -> Observable<User>
}

class Example {
    let service: ContentService
    init(service: ContentService) {
        self.service = service
    }

    func bind(trigger: Observable<String>) -> Observable<(Article, User)> {
        let service = self.service
        return trigger
            .flatMapLatest { service.requestArticle(id: [=10=]) }
            .flatMapLatest {
                Observable.combineLatest(Observable.just([=10=]), service.requestProfile(id: [=10=].authorId))
            }
    }
}

或者您可能希望在等待作者个人资料下载时显示文章。在那种情况下是这样的:

func bind(trigger: Observable<String>) -> (article: Observable<Article>, author: Observable<User>) {
    let service = self.service
    let article = trigger
        .flatMapLatest { service.requestArticle(id: [=11=]) }
        .share(replay: 1)

    let author = article
        .flatMapLatest {
            service.requestProfile(id: [=11=].authorId)
    }

    return (article, author)
}