基于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
相关产品推荐
相关产品推荐

