首页 > 解决方案 > 使用 RxSwift 链接请求并返回两个结果

问题描述

我有ContentService一个请求一篇文章的请求。该文章响应包含一个authorId属性。

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

我正在尝试从ContentService, 链上请求一篇文章,一旦完成ProfileService使用该authorId属性,我想返回一个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: $0)) }
            .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: $0)) }
            .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: $0, user: $1) }
            .bind(to: output.fetchArticleResponse)
            .disposed(by: disposeBag)
    }

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

但是,我不确定这是否正确。

标签: swiftrx-swiftchaining

解决方案


我不确定为什么你有这么多代码来完成这么小的工作。下面是一个示例,它执行您所描述的操作(下载文章,下载作者个人资料并发出两者),代码少得多,甚至比我通常使用的代码多

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: $0) }
            .flatMapLatest {
                Observable.combineLatest(Observable.just($0), service.requestProfile(id: $0.authorId))
            }
    }
}

或者,您可能希望在等待作者简介下载时显示文章。在这种情况下是这样的:

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

    let author = article
        .flatMapLatest {
            service.requestProfile(id: $0.authorId)
    }

    return (article, author)
}

推荐阅读