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

SwiftUI绑定ViewModel错误的Alert仅首次显示后续不弹出问题求助

问题原因

  1. SwiftUI的alert(isPresented:)触发弹窗的前提是绑定的布尔值产生false → true的状态切换。你当前代码中自定义的hasError绑定的setter为空,点击Alert的OK按钮关闭弹窗时,系统会尝试将绑定值设为false,但这个操作没有同步把ViewModel中的error属性置为nil,导致hasError的getter一直返回true。
  2. 后续再次发起请求失败时,即使重新给error赋值,如果新赋值的error和旧值相等,@Published属性不会发出状态更新通知,也就不会产生false → true的状态变化,SwiftUI检测不到状态切换就不会重新弹出Alert。

解决方案

步骤1:修改ViewModel逻辑

每次发起请求前先重置error为空,保证新请求的错误状态可以正常触发状态更新:

class LanguageViewModel: ObservableObject {
    var subscriptions: Set<AnyCancellable> = []

    @Published private(set) var languages: [LanguageItem]?
    @Published private(set) var error: Error?

    func get() {
        // 发起请求前先重置错误状态
        error = nil
        APIService.fetchData()
            .receive(on: DispatchQueue.main)
            .sink(receiveCompletion: { [weak self] value in
                guard let self = self else { return }
                if case let .failure(error) = value {
                    self.error = error
                }

            }, receiveValue: { (data: [LanguageItem]) in
                self.languages = data

            })
            .store(in: &self.subscriptions)
    }

    // 新增错误重置方法,供关闭弹窗时调用
    func resetError() {
        error = nil
    }
}

步骤2:修正Binding逻辑

完善hasError绑定的setter实现,关闭弹窗时同步清空ViewModel的错误状态:

struct ContentView: View {
    @ObservedObject private var languageViewModel = LanguageViewModel()

    var body: some View {
        let hasError = Binding<Bool>(
            get: { self.languageViewModel.error != nil },
            set: { newValue in
                // 弹窗关闭时重置错误状态
                if !newValue {
                    self.languageViewModel.resetError()
                }
            }
        )

        Button(action: {
            self.languageViewModel.get()
        }) {
            Text("Hello, World")
        }
        .alert(isPresented: hasError) {
            let message = self.languageViewModel.error?.localizedDescription
            return Alert(title: Text("Error"), message: Text(message ?? ""), dismissButton: .default(Text("OK")))
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 15:54:05