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

SwiftUI二次跳转页面时Alert无法显示的问题排查

问题原因分析
  1. NWPathMonitor重复启动异常:每次进入DashboardView调用getDashboardData时,都会重复执行monitor.start(queue: queue)。NWPathMonitor不允许多次启动,重复调用会导致路径更新处理器(pathUpdateHandler)无法正常触发,进而无法设置appError,Alert自然不会弹出。
  2. ViewModel持有方式错误:使用@ObservedObject持有DashboardViewModel,当返回上一页再进入时,若View未被完全销毁可能复用旧ViewModel;若View被销毁,旧ViewModel的NWPathMonitor未正确停止,会干扰新实例的网络状态检测。
  3. 未主动触发当前网络状态检测:默认情况下NWPathMonitor仅在网络状态变化时触发pathUpdateHandler,若网络状态无变化,第二次进入时不会主动检测当前状态,导致无法及时设置错误信息。
解决方案

1. 修正ViewModel持有方式

将@ObservedObject改为@StateObject,确保ViewModel在View生命周期内唯一且稳定:

struct DashboardView: View {
    // 替换@ObservedObject为@StateObject
    @StateObject var viewModel = DashboardViewModel()
    // ... 其余代码不变
}

2. 正确管理NWPathMonitor生命周期

在DashboardViewModel中仅初始化时启动监控,销毁时停止,避免重复启动:

class DashboardViewModel: ObservableObject, FetchDashboardDataFromServer {
    // ... 已有代码
    
    init() {
        self.currentState = .LOADING
        // 在init中初始化监控逻辑
        monitor.pathUpdateHandler = { [weak self] path in
            guard let self = self else { return }
            DispatchQueue.main.async {
                if path.status == .satisfied {
                    self.fetchDashboardDataFromAPI()
                } else {
                    self.currentState = .FAILURE(error: StringConstants.NoInterNet)
                    self.appError = AppError(errorString: StringConstants.NoInterNet)
                }
            }
        }
        monitor.start(queue: queue)
    }
    
    // 分离API请求逻辑
    private func fetchDashboardDataFromAPI() {
        self.currentState = .LOADING
        APIClient.dispatch(
            APIRouter.GetDashboardData(queryParams:
            APIParameters.GetDasbhboardParams(apikey: "API_KEY")))
        .sink { [weak self] completion in
            guard let self = self else { return }
            switch completion {
            case .finished:
                print("Execution Finished dashboard.")
            case .failure(let error):
                DispatchQueue.main.async {
                    print("dashboard error", error)
                    self.appError = AppError(errorString: error.localizedDescription)
                    self.currentState = .FAILURE(error: error.localizedDescription)
                }
            }
        } receiveValue: { [weak self] dashboardData in
            guard let self = self else { return }
            print("received dashboard data", dashboardData)
            self.currentState = .SUCCESS(dashboardModel: dashboardData)
        }.store(in: &self.cancelable)
    }
    
    // 重写getDashboardData,主动触发状态检查
    func getDashboardData() {
        print("fetch dashboard data")
        // 主动获取当前网络状态并处理
        if let currentPath = monitor.currentPath {
            DispatchQueue.main.async {
                if currentPath.status == .satisfied {
                    self.fetchDashboardDataFromAPI()
                } else {
                    self.currentState = .FAILURE(error: StringConstants.NoInterNet)
                    self.appError = AppError(errorString: StringConstants.NoInterNet)
                }
            }
        }
    }
    
    // 销毁时停止监控并取消请求
    deinit {
        monitor.cancel()
        cancelable.forEach { $0.cancel() }
    }
}

3. 调整onAppear位置

将onAppear移到父容器上,确保每次View出现时都调用getDashboardData:

var body: some View {
    ZStack {
        // ... 原有视图内容
    }
    .navigationBarTitle("Dashboard", displayMode: .inline)
    .alert(item: $viewModel.appError) { appAlert in
        Alert(title: Text("Error"),
              message: Text("""
                \(appAlert.errorString)
                Please try again later!
                """
              )
        )
    }
    .ignoresSafeArea(.all)
    // 将onAppear移到此处,确保每次View出现都触发
    .onAppear(perform: viewModel.getDashboardData)
}
关键说明
  • @StateObject确保ViewModel在View生命周期内仅初始化一次,避免重复创建导致的资源泄漏和状态混乱。
  • NWPathMonitor仅启动一次,销毁时停止,避免重复启动引发的异常。
  • 主动获取当前网络状态,确保每次进入View都能触发对应的错误处理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:01:20