SwiftUI中NavigationLink跳转后立即返回的问题求助
SwiftUI + Firebase 注册后跳转自动返回问题
我用SwiftUI搭配Firebase做后端开发应用,想要实现:点击Sign Up按钮后,把用户填写的信息存到Firebase数据库,然后跳转到ProfilePhotoSelecterView并停留在该页面。但实际测试时,点击按钮后虽然能跳转到照片选择页面,但立刻自动返回注册页面。
我用了带destination、isActive和label参数的NavigationLink,通过@Published修饰的布尔属性didAuthenciateUser控制激活状态。以下是相关代码:
@main 视图代码
import SwiftUI import Firebase @main struct Twitter_Demo_YoutubeApp: App { @StateObject var viewModel = AuthViewModel() init() { FirebaseApp.configure() } var body: some Scene { WindowGroup { NavigationView { ContentView() } .environmentObject(viewModel) } } }
ContentView 代码
import SwiftUI struct ContentView: View { @State private var showManu = false @EnvironmentObject var viewModel: AuthViewModel var body: some View { Group { // 未登录状态 if viewModel.userSession == nil { LoginView() } else { // 已登录状态 mainInterfaceView } } } } #Preview { ContentView() } extension ContentView { var mainInterfaceView: some View { ZStack(alignment: .topLeading) { MainTabView() .navigationBarHidden(showManu) if showManu { ZStack { Color(.black) .opacity(showManu ? 0.25: 0.0) }.onTapGesture { withAnimation(.easeInOut) { showManu = false } } .ignoresSafeArea() } SideManuView() .frame(width: 300) .offset(x: showManu ? 0 : -300, y: 0) .background(showManu ? Color.white : Color.clear) } .navigationTitle("Home") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarLeading) { Button { withAnimation(.easeInOut) { showManu.toggle() } } label: { Circle() .frame(width: 32, height: 32) } } } .onAppear { showManu = false } } }
AuthViewModel 代码
class AuthViewModel: ObservableObject { @Published var userSession: FirebaseAuth.User? @Published var didAuthenciateUser = false init() { self.userSession = Auth.auth().currentUser } func register(withEmail email: String, password: String, fullname: String, username: String) { Auth.auth().createUser(withEmail: email, password: password) { result, error in if let error = error { return } guard let user = result?.user else { return } let data = [ "email": email, "username": username.lowercased(), "fullname": fullname, "uid": user.uid] Firestore.firestore().collection("users") .document(user.uid) .setData(data) { _ in self.didAuthenciateUser = true } } } }
RegistrationView 代码
import SwiftUI struct RegistrationView: View { @State private var email = "" @State private var username = "" @State private var fullname = "" @State private var password = "" @Environment(\.presentationMode) var presentationMode @EnvironmentObject var viewModel: AuthViewModel var body: some View { VStack { NavigationLink(destination: ProfilePhotoSelecterView(), isActive: $viewModel.didAuthenciateUser, label: { }) // 控制跳转的NavigationLink AuthHeaderView(title1: "Get started.", title2: "Create your account") VStack(spacing: 40) { CustomInputField(imageName: "envelope", placeholderText: "Email", text: $email) CustomInputField(imageName: "person", placeholderText: "username", text: $username) CustomInputField(imageName: "person", placeholderText: "Full Name", text: $fullname) CustomInputField(imageName: "lock", placeholderText: "Password", isSecureField: true, text: $password) } .padding(32) Button { viewModel.register(withEmail: email, password: password, fullname: fullname, username: username) } label: { Text("Sign Up") .font(.headline) .foregroundColor(.white) .frame(width: 340, height: 50) .background(Color(.systemBlue)) .clipShape(Capsule()) .padding() } .shadow(color: .gray.opacity(0.5), radius: 10, x: 0, y: 0) Spacer() Button { presentationMode.wrappedValue.dismiss() } label: { HStack { Text("Already have account?") .font(.footnote) Text("Sign In") .font(.footnote) .fontWeight(.semibold) } } .padding(.bottom, 32) } .ignoresSafeArea() } } #Preview { RegistrationView() }
ProfilePhotoSelecterView 代码
import SwiftUI struct ProfilePhotoSelecterView: View { var body: some View { VStack { AuthHeaderView(title1: "Create your account.", title2: "Add a profile photo") Button { print("Pick image here..") } label: { Image("addphoto") .resizable() .scaledToFill() .frame(width: 180, height: 180) .padding(.top, 44) } Spacer() } .ignoresSafeArea() } } #Preview { ProfilePhotoSelecterView() }
相关截图说明
- 初始页面:显示注册输入界面,包含邮箱、用户名、全名、密码输入框和Sign Up按钮
- 点击Sign Up按钮后的异常页面:短暂显示的照片选择页面,提示添加头像
- 最终返回页面:回到初始的注册输入界面
问题原因
注册成功后,你既没有及时更新userSession,也没有处理导航状态的重置逻辑:
- 注册成功后
userSession仍为nil,ContentView会持续显示登录/注册流程的视图,当导航栈切换时会销毁ProfilePhotoSelecterView didAuthenciateUser状态在跳转后没有重置,会导致导航逻辑混乱
解决步骤
1. 修改AuthViewModel,拆分注册与登录流程
新增临时变量存储刚注册的用户,等头像设置完成后再正式激活用户会话:
class AuthViewModel: ObservableObject { @Published var userSession: FirebaseAuth.User? @Published var didAuthenciateUser = false private var tempRegisteredUser: FirebaseAuth.User? // 临时存储刚注册的用户 init() { self.userSession = Auth.auth().currentUser } func register(withEmail email: String, password: String, fullname: String, username: String) { Auth.auth().createUser(withEmail: email, password: password) { result, error in guard error == nil, let user = result?.user else { print(error?.localizedDescription ?? "注册失败") return } self.tempRegisteredUser = user let userData = [ "email": email, "username": username.lowercased(), "fullname": fullname, "uid": user.uid, "profileImageUrl": "" ] Firestore.firestore().collection("users").document(user.uid).setData(userData) { _ in self.didAuthenciateUser = true // 触发跳转到头像选择页 } } } // 完成头像设置后正式登录 func completeProfile(withImageUrl imageUrl: String) { guard let user = tempRegisteredUser else { return } Firestore.firestore().collection("users").document(user.uid).updateData([ "profileImageUrl": imageUrl ]) { _ in self.userSession = user self.didAuthenciateUser = false self.tempRegisteredUser = nil } } }
2. 调整ProfilePhotoSelecterView,处理状态重置与头像设置逻辑
添加环境对象绑定,跳转后重置导航状态,并预留头像上传完成后的回调:
import SwiftUI struct ProfilePhotoSelecterView: View { @EnvironmentObject var viewModel: AuthViewModel var body: some View { VStack { AuthHeaderView(title1: "Create your account.", title2: "Add a profile photo") Button { // 替换为实际图片选择逻辑,示例: // viewModel.completeProfile(withImageUrl: "你的头像URL") print("Pick image here..") } label: { Image("addphoto") .resizable() .scaledToFill() .frame(width: 180, height: 180) .padding(.top, 44) } Spacer() } .ignoresSafeArea() .onAppear { viewModel.didAuthenciateUser = false // 重置状态避免重复跳转 } } } #Preview { ProfilePhotoSelecterView() }
3. 保持ContentView原有逻辑
无需修改ContentView的判断逻辑,因为注册流程未完成时userSession始终为nil,LoginView的导航栈会完整保留,不会打断跳转后的ProfilePhotoSelecterView。
内容的提问来源于stack exchange,提问作者user21666271
相关产品推荐
相关产品推荐

