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

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无法感知网络状态的变化。同时,重试时未重置错误状态,即使请求成功也可能停留在错误页面。

修复步骤

  1. 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
                }
            }
        }
    }
    
  2. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 05:35:21