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

SwiftUI登录视图跳转后自动返回问题求助

SwiftUI登录成功后自动返回登录页的问题修复

我用SwiftUI开发了登录视图,通过UserDefaults校验用户名和密码,验证通过后跳转至FirstView。但成功登录后会自动返回登录视图,仅重启应用后功能正常。尝试简化实现却不知该修改哪里,相关代码如下:


@main文件代码

@main
struct demoApp: App {
    @StateObject var dataController =  DataController.shared
    init() {
        UserDefaults.standard.register(defaults: [
            "username": "test@test.com", "password": "demo", "logData": false
        ])
    }
    let userInfo = UserDefaults.standard.bool(forKey: "logData")
    var body: some Scene {
        WindowGroup {
            ContentView(data: dataController)
                .environment(\.managedObjectContext, dataController.container.viewContext)
        }
    }
}

初始登录页代码

struct LoginPage: View {
    @State var username: String = ""
    @State var password: String = ""
    let userData = UserDefaults.standard.string(forKey: "username")
    let userPassword = UserDefaults.standard.string(forKey: "password")
    @State var credStatus = false
    @State var showerroralert = false
    @ObservedObject var data: DataController
    var body: some View {
        NavigationStack {
            VStack {
                Text("Welcome")
                    .font(.title)
                Image("carbg")
                    .resizable()
                    .cornerRadius(20)
                    .frame(width: 150, height: 150)
                TextField("Username", text: $username)
                    .padding()
                    .cornerRadius(5.0)
                    .padding(.bottom, 20)
                SecureField("Password", text: $password)
                    .padding()
                    .cornerRadius(5.0)
                    .padding(.bottom, 20)
                Button("Login") {
                    if (userData == username && userPassword == password) {
                        credStatus = true
                        UserDefaults.standard.set(true, forKey: "logData")
                    } else {
                        showerroralert = true
                    }
                }
                .buttonStyle(.borderedProminent)
                .alert("Wrong data", isPresented: $showerroralert) {
                }
            }
            .navigationDestination(isPresented: $credStatus) {
                ContentView(data: data)
            }
        }
    }
}

ContentView代码

struct ContentView: View {
    @ObservedObject var data: DataController
    @State var userInfo = UserDefaults.standard.bool(forKey: "logData")
    var body: some View {
        if userInfo {
            FirstView()
        } else {
            LoginPage(data: data)
        }
    }
}

更新后的登录页代码

struct LoginPage: View {
    @State var usernameTemp: String = ""
    @State var passwordTemp: String = ""
    @State var credStatus = false
    @State var showerroralert = false
    @ObservedObject var data: DataController
    @AppStorage("username") var username: String = "test@demo.tech"
    @AppStorage("password") var password: String = "demo"
    @AppStorage("logData") var logData: Bool = false
    var body: some View {
        NavigationStack {
            VStack {
                Text("Welcome")
                    .font(.title)
                Image("carbg")
                    .resizable()
                    .cornerRadius(20)
                    .frame(width: 150, height: 150)
                TextField("Username", text: $usernameTemp)
                    .padding()
                    .cornerRadius(5.0)
                    .padding(.bottom, 20)
                SecureField("Password", text: $passwordTemp)
                    .padding()
                    .cornerRadius(5.0)
                    .padding(.bottom, 20)
                Button("Login") {
                    if (usernameTemp == username && passwordTemp == password) {
                        credStatus = true
                        logData = true
                    } else {
                        showerroralert = true
                    }
                }
                .buttonStyle(.borderedProminent)
                .alert("Wrong data", isPresented: $showerroralert) {
                }
            }
            .navigationDestination(isPresented: $credStatus) {
                ContentView(data: data)
            }
        }
    }
}

问题原因及修复方案

核心问题

  1. ContentView的登录状态未实时监听:用@State存储userInfo只会在视图初始化时读取一次UserDefaults的值,登录后更新logData不会触发ContentView刷新,导致视图仍停留在登录页。
  2. 跳转逻辑冲突:登录页既通过navigationDestination跳转到ContentView,又设置logData标记登录状态,而ContentView本身会根据logData切换视图,导致导航栈出现循环,最终自动返回登录页。

具体修复步骤

1. 让ContentView实时监听登录状态

将ContentView中的@State var userInfo替换为@AppStorage("logData"),这样UserDefaults的值变化时会自动触发视图刷新:

struct ContentView: View {
    @ObservedObject var data: DataController
    @AppStorage("logData") var userInfo: Bool = false // 替换原@State变量
    var body: some View {
        if userInfo {
            FirstView()
        } else {
            LoginPage(data: data)
        }
    }
}

2. 简化登录页的跳转逻辑

登录成功后仅需设置logData为true,无需手动跳转,ContentView会自动切换到FirstView。同时移除登录页的NavigationStack:

struct LoginPage: View {
    @State var usernameTemp: String = ""
    @State var passwordTemp: String = ""
    @State var showerroralert = false
    @ObservedObject var data: DataController
    @AppStorage("username") var username: String = "test@demo.tech"
    @AppStorage("password") var password: String = "demo"
    @AppStorage("logData") var logData: Bool = false
    
    var body: some View {
        VStack {
            Text("Welcome")
                .font(.title)
            Image("carbg")
                .resizable()
                .cornerRadius(20)
                .frame(width: 150, height: 150)
            TextField("Username", text: $usernameTemp)
                .padding()
                .cornerRadius(5.0)
                .padding(.bottom, 20)
            SecureField("Password", text: $passwordTemp)
                .padding()
                .cornerRadius(5.0)
                .padding(.bottom, 20)
            Button("Login") {
                if usernameTemp == username && passwordTemp == password {
                    logData = true // 仅设置登录状态,ContentView自动切换视图
                } else {
                    showerroralert = true
                }
            }
            .buttonStyle(.borderedProminent)
            .alert("账号或密码错误", isPresented: $showerroralert) {
            }
        }
    }
}

3. 优化@main文件

移除@main中多余的userInfo变量,保持默认值注册逻辑即可:

@main
struct demoApp: App {
    @StateObject var dataController = DataController.shared
    
    init() {
        UserDefaults.standard.register(defaults: [
            "username": "test@test.com", 
            "password": "demo", 
            "logData": false
        ])
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView(data: dataController)
                .environment(\.managedObjectContext, dataController.container.viewContext)
        }
    }
}

修复原理

  • @AppStorage是SwiftUI提供的与UserDefaults绑定的属性包装器,能自动监听键值变化并刷新视图,解决了@State无法实时更新的问题。
  • 让ContentView作为根视图统一管理登录状态和视图切换,避免手动跳转导致的导航栈循环,从根源上解决自动返回的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 04:55:13