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

SwiftUI注销完成后如何自动跳转至Register根视图?

解决SwiftUI注销后视图不自动刷新的问题

你的核心问题是ContentView没有监听UserDefaults的变化,直接在body里读取UserDefaults不会触发视图刷新。下面提供两种实用方案:

方案一:使用@AppStorage快速实现(适合简单场景)

@AppStorage是SwiftUI提供的直接绑定UserDefaults的属性包装器,会自动监听值的变化并刷新视图。

修改ContentView

struct ContentView: View {
    // 绑定UserDefaults中的"sessionKey",自动同步状态
    @AppStorage("sessionKey") private var sessionKey: String?

    var body: some View {
        if let key = sessionKey {
            MainPage()
        } else {
            Register()
        }
    }
}

修改LogOutView

注销成功后直接设置sessionKey为nil,@AppStorage会自动同步到UserDefaults并触发ContentView刷新:

struct LogOutView: View {
    @StateObject var loginModel = LoginViewModel()
    @AppStorage("sessionKey") private var sessionKey: String?

    var body: some View {
        VStack {
            Button(action: {
                print("Log Out Tapped...")
                guard let key = sessionKey else { return }
                
                loginModel.logOut(key: key) { success in
                    if success {
                        sessionKey = nil // 自动同步到UserDefaults,触发视图切换
                    }
                }
            }, label: {
                Text("Log Out")
            })
        }
    }
}

方案二:使用共享ViewModel(适合复杂登录状态管理)

如果你的APP有更多登录相关逻辑(比如用户信息、token校验等),推荐把登录状态统一放到ViewModel中,用@Published实现响应式刷新。

优化LoginViewModel

把sessionKey作为@Published属性,自动同步UserDefaults:

class LoginViewModel: ObservableObject {
    @Published var sessionKey: String? {
        didSet {
            // 自动同步到UserDefaults
            if let key = sessionKey {
                UserDefaults.standard.set(key, forKey: "sessionKey")
            } else {
                UserDefaults.standard.removeObject(forKey: "sessionKey")
            }
        }
    }

    // 初始化时从UserDefaults读取状态
    init() {
        sessionKey = UserDefaults.standard.string(forKey: "sessionKey")
    }

    func logOut(key: String, completion: @escaping (Bool) -> Void) {
        // 原有的API注销逻辑
        // 调用成功后直接更新sessionKey
        completion(true)
        sessionKey = nil
    }
}

修改ContentView

使用@StateObject创建共享的ViewModel,并通过environmentObject传递给子视图:

struct ContentView: View {
    @StateObject private var loginModel = LoginViewModel()

    var body: some View {
        if let key = loginModel.sessionKey {
            MainPage()
                .environmentObject(loginModel)
        } else {
            Register()
                .environmentObject(loginModel)
        }
    }
}

修改LogOutView

通过@EnvironmentObject获取共享的ViewModel,无需重复创建:

struct LogOutView: View {
    @EnvironmentObject var loginModel: LoginViewModel

    var body: some View {
        VStack {
            Button(action: {
                print("Log Out Tapped...")
                guard let key = loginModel.sessionKey else { return }
                
                loginModel.logOut(key: key) { success in
                    // 无需手动操作UserDefaults,ViewModel已自动处理
                }
            }, label: {
                Text("Log Out")
            })
        }
    }
}

为什么原有代码不生效?

SwiftUI的视图刷新只依赖响应式状态(比如@State、@Binding、@Published、@AppStorage等),直接在body中读取UserDefaults属于一次性读取,不会监听后续变化,所以注销后ContentView不会自动刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:43:17