SwiftUI无网络错误页问题:恢复网络后无法切换至用户页
网络恢复后错误页面无法正常刷新的问题排查与修复
问题描述
实现无网络错误场景时出现异常:进入PersonalDataScreen后断网,再次进入会显示ErrorScreen;但恢复网络后点击重试按钮,仍持续显示无网络页面。调试发现viewModel.networkMonitor.isConnected始终为false,实际网络已恢复,仅能通过重启应用恢复正常。
当前表现
- 进入PersonalDataScreen后断网,再次进入显示无网络ErrorScreen
- 恢复网络后返回,仍停留在错误页面无法跳转
presentingUnknownError场景存在相同问题
期望效果
- 恢复网络后点击错误页重试按钮,可重新加载并显示UserProfileScreen
- 修复未知错误场景下的相同刷新问题
相关代码
屏幕代码
struct PersonalDataScreen: View { @ObservedObject var viewModel: PersonalDataViewModel @Injected private var config: PersonalDataJourney.Configuration init(viewModel: PersonalDataViewModel) { self.viewModel = viewModel viewModel.fetchUserProfileData() } var body: some View { let strings = config.strings VStack { if viewModel.presentingLoader { LoaderView() } else { if !viewModel.networkMonitor.isConnected { ErrorScreen(title: strings.noInternetTitle, subtitle: strings.noInternetDescription, button: strings.errorButton) { viewModel.fetchUserProfileData() } } else if viewModel.presentingUnknownError { ErrorScreen(title: strings.techicalErrorTitle, subtitle: strings.technicalErrorDescription, button: strings.errorButton) { viewModel.fetchUserProfileData() } } else { UserProfileScreen() } } } } }
ViewModel代码
class PersonalDataViewModel: ObservableObject { @Injected private var personalDataUseCase: PersonalDataUseCaseProtocol @ObservedObject public var networkMonitor = NetworkMonitor.shared @Published var personalDataAssetsData: PersonalDataAssetsData? @Published var presentingLoader = false @Published var presentingUnknownError = false func fetchUserProfileData() { presentingLoader = true personalDataUseCase.performPersonalDataRequest { [weak self] result in self?.presentingLoader = false switch result { case .success(let response): self?.personalDataAssetsData = response case .failure: self?.presentingUnknownError = true } } } }
NetworkMonitor代码
class NetworkMonitor: ObservableObject { private let monitor = NWPathMonitor() private let queue = DispatchQueue(label: "NetworkMonitor") @Published var isConnected = true static let shared: NetworkMonitor = { NetworkMonitor() }() init() { monitor.pathUpdateHandler = { path in DispatchQueue.main.async { self.isConnected = path.status == .satisfied } } monitor.start(queue: queue) } }
解决方案
核心问题分析
ViewModel中使用@ObservedObject修饰networkMonitor,但ViewModel本身是ObservableObject,内部@ObservedObject的属性变化不会触发ViewModel向View发送更新通知,导致View无法感知网络状态的变化。同时,重试时未重置错误状态,即使请求成功也可能停留在错误页面。
修复步骤
ViewModel中监听网络状态并同步到本地@Published属性
将NetworkMonitor的状态变化映射到ViewModel自己的@Published属性,确保View能感知到网络状态更新:class PersonalDataViewModel: ObservableObject { @Injected private var personalDataUseCase: PersonalDataUseCaseProtocol private let networkMonitor = NetworkMonitor.shared @Published var isNetworkConnected = true @Published var personalDataAssetsData: PersonalDataAssetsData? @Published var presentingLoader = false @Published var presentingUnknownError = false private var cancellables = Set<AnyCancellable>() init() { // 监听网络状态变化,同步到本地@Published属性 networkMonitor.$isConnected .assign(to: \.isNetworkConnected, on: self) .store(in: &cancellables) } func fetchUserProfileData() { presentingLoader = true presentingUnknownError = false // 重试时重置错误状态 personalDataUseCase.performPersonalDataRequest { [weak self] result in self?.presentingLoader = false switch result { case .success(let response): self?.personalDataAssetsData = response self?.presentingUnknownError = false case .failure: self?.presentingUnknownError = true } } } }修改View中的网络状态判断逻辑
替换原有的viewModel.networkMonitor.isConnected为ViewModel的isNetworkConnected属性:var body: some View { let strings = config.strings VStack { if viewModel.presentingLoader { LoaderView() } else { if !viewModel.isNetworkConnected { ErrorScreen(title: strings.noInternetTitle, subtitle: strings.noInternetDescription, button: strings.errorButton) { viewModel.fetchUserProfileData() } } else if viewModel.presentingUnknownError { ErrorScreen(title: strings.techicalErrorTitle, subtitle: strings.technicalErrorDescription, button: strings.errorButton) { viewModel.fetchUserProfileData() } } else { UserProfileScreen() } } } }
额外优化点
- 在
fetchUserProfileData方法开头重置presentingUnknownError状态,避免重试时因之前的错误状态导致页面不更新 - 确保NetworkMonitor的单例初始化正确,避免重复创建实例(现有代码已满足)
内容的提问来源于stack exchange,提问作者user20273483
相关产品推荐
相关产品推荐

