You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于RxSwift Subject实现父VC(A)向切换子VC(B/C)传递请求响应数据

用RxSwift实现父VC网络响应的子VC共享方案

嘿,刚接触RxSwift不用慌~这个场景正好能发挥Rx响应式的优势,让父VC的网络请求结果自动同步给两个子VC。我给你梳理一个清晰的实现步骤,结合你的现有代码来改:

1. 在父VC的ViewModel中创建共享的响应Subject

首先,我们需要把网络请求得到的ProfileResponse做成一个可被订阅的Subject,这样子VC就能监听它的变化。推荐用BehaviorSubject,它会保存最新的响应值,哪怕子VC是在请求完成后才被添加进来,也能立刻拿到最新数据。

修改你的ViewModel代码:

class ProfileParentViewModel {
    // 保留你已有的其他Subject/Property
    let startedUp = PublishSubject<Bool>()
    let loadInProgress = PublishSubject<Bool>()
    let errorsSubject = PublishSubject<Error>()
    let sectionSubject = PublishSubject<Int>()
    // 新增共享响应的BehaviorSubject,初始值设为nil
    let profileResponse = BehaviorSubject<ProfileResponse?>(value: nil)
    private let disposeBag = DisposeBag()

    func fetchProfile() {
        startedUp.accept(true)
        startedUp.filter({ $0})
            .flatMap{ [weak self] _ -> Observable<Event<Result<ProfileResponse>>> in
                self?.loadInProgress.accept(true)
                return network.showProfile(startupId: 1).materialize()
            }
            .subscribe(onNext: { [weak self] event in
                guard let self = self else { return }
                self.loadInProgress.accept(false)
                switch event {
                case .next(let result):
                    switch result{
                    case .Success(let response):
                        self.startedUp.accept(false)
                        self.sectionSubject.onNext(0)
                        // 把响应发送到共享Subject中
                        self.profileResponse.onNext(response)
                    case .Failure(let error):
                        self.errorsSubject.onNext(error)
                    }
                case .error(let error):
                    print("请求出错: \(error.localizedDescription)")
                default:
                    break
                }
            })
            .disposed(by: disposeBag)
    }
}

2. 给子VC添加订阅逻辑

接下来,在两个子VC(ProfileVC和SocialMediaVCViewController)中,添加对父ViewModel的profileResponse的订阅,这样就能在数据更新时自动刷新UI。

以ProfileVC为例:

class ProfileVC: UIViewController {
    // 持有父ViewModel的引用
    var parentViewModel: ProfileParentViewModel?
    private let disposeBag = DisposeBag()
    // 保留你已有的UI相关属性
    var editProfileData: YourDataType!
    let tableViewcellsSubject = PublishSubject<[YourCellType]>()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupProfileSubscription()
    }

    private func setupProfileSubscription() {
        parentViewModel?.profileResponse
            // 过滤掉nil值,只处理有效的响应
            .filter({ $0 != nil })
            .map({ $0! })
            .subscribe(onNext: { [weak self] response in
                // 在这里处理你的UI更新逻辑
                self?.updateProfileUI(with: response)
            }, onError: { error in
                print("订阅Profile数据出错: \(error)")
            })
            .disposed(by: disposeBag)
    }

    private func updateProfileUI(with response: ProfileResponse) {
        // 把你原来的setProfileData、createArray逻辑移到这里
        self.editProfileData = self.setProfileData(response: response)
        self.tableViewcellsSubject.onNext(self.createArray(response: response))
    }

    // 保留你原来的setProfileData、createArray方法
    private func setProfileData(response: ProfileResponse) -> YourDataType {
        // 原逻辑
    }

    private func createArray(response: ProfileResponse) -> [YourCellType] {
        // 原逻辑
    }
}

SocialMediaVCViewController的逻辑类似,只需要把订阅后的UI处理换成对应的社交数据逻辑即可:

class SocialMediaVCViewController: UIViewController {
    var parentViewModel: ProfileParentViewModel?
    private let disposeBag = DisposeBag()
    let userscellsSubject = PublishSubject<[YourUserCellType]>()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupSocialMediaSubscription()
    }

    private func setupSocialMediaSubscription() {
        parentViewModel?.profileResponse
            .filter({ $0 != nil })
            .map({ $0! })
            .subscribe(onNext: { [weak self] response in
                guard let users = response.users else { return }
                self?.userscellsSubject.onNext(self?.createUserArray(response: users) ?? [])
            })
            .disposed(by: disposeBag)
    }

    private func createUserArray(response: [User]) -> [YourUserCellType] {
        // 原逻辑
    }
}

3. 在父VC中给子VC传递ViewModel

最后,在父VC初始化子VC的时候,把ViewModel传递给它们:

修改父VC的子VC初始化代码:

// 假设你的父VC持有ViewModel实例
private let viewModel = ProfileParentViewModel()

private lazy var profileVC: ProfileVC = {
    let storyboard = UIStoryboard(name: "Profile", bundle: Bundle.main)
    let viewController = storyboard.instantiateViewController(withIdentifier: "ProfileVC") as! ProfileVC
    // 传递ViewModel
    viewController.parentViewModel = self.viewModel
    self.add(asChildViewController: viewController)
    return viewController
}()

private lazy var socialMediaVC: SocialMediaVCViewController = {
    let storyboard = UIStoryboard(name: "Profile", bundle: Bundle.main)
    let viewController = storyboard.instantiateViewController(withIdentifier: "SocialMediaVC") as! SocialMediaVCViewController
    viewController.parentViewModel = self.viewModel
    self.add(asChildViewController: viewController)
    return viewController
}()

额外注意事项

  • 内存泄漏:子VC中用disposeBag管理订阅,当子VC被销毁时,订阅会自动取消,不用担心内存问题。
  • 错过初始数据:用BehaviorSubject而不是PublishSubject的原因是,它会保存最新的响应值,即使子VC在请求完成后才被添加,也能立刻拿到最新数据,避免错过更新。
  • 错误处理:可以在子VC的订阅中添加onError回调,统一处理错误情况。

这样一来,不管你切换到哪个子VC,只要父VC的网络请求完成,子VC都会自动收到数据并更新UI,完美实现你的需求~

内容的提问来源于stack exchange,提问作者George2456

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:52:49