NavigationStack跳转子视图后自动返回根视图问题排查
导航栈自动返回根视图问题排查与解决
使用NavigationStack时遇到问题:打开子视图后会自动返回根视图。移除messengerLogic.fetchMessages函数的.onAppear调用后,导航功能恢复正常,推测问题与消息获取操作相关。
相关代码
根视图与收件箱视图
struct TabBar: View { @StateObject private var messengerLogic = MessengerLogic() init() { UITabBar.appearance().backgroundColor = UIColor(Color("PrimaryGray")) UITabBar.appearance().barTintColor = .black UITabBar.appearance().unselectedItemTintColor = UIColor(Color("PrimaryBlue")) } var body: some View { TabView { // 其他标签页... ForEach(influencerTabs, id: \.title) { tab in tab.view .tabItem { Image(systemName: tab.iconName) Text(tab.title) } } } } // 博主标签页列表 private var influencerTabs: [Tab] { [ Tab(view: AnyView(InfluencerMainProfile().environmentObject(influencerUserModel)), iconName: "person.circle", title: "Profile"), Tab(view: AnyView(MessengerInbox().environmentObject(messengerLogic)), iconName: "message", title: "Messages") ] } } struct MessengerInbox: View { @EnvironmentObject var messengerLogic: MessengerLogic var body: some View { NavigationStack { ScrollView { VStack(spacing: 1) { ForEach(messengerLogic.recentMessages) { chat in NavigationLink { MessengerMainView(userId: chat.toId, businessName: chat.businessName, businessProfilePicture: chat.profileImageUrl) .environmentObject(messengerLogic) } label: { InboxRow(userId: chat.toId , userName: chat.businessName , recentMessage: chat.text , timestamp: chat.timestamp , businessProfilePicture: chat.profileImageUrl ) } } .padding(.top) } } } } } // 聊天主视图 struct MessengerMainView: View { @EnvironmentObject var messengerLogic: MessengerLogic var userId: String // 消息接收方ID var businessName: String var businessProfilePicture: String @State private var newMessage: String = "" var body: some View { ScrollView { VStack { ForEach(messengerLogic.chatMessages){ message in HStack(alignment: .top, spacing: 12) { Image(systemName: message.profileImage ) .resizable() .frame(width: 40, height: 40) VStack(alignment: .leading, spacing: 4) { Text(message.senderName) .font(.headline) .foregroundColor(.primary) Text(message.messageText) .font(.body) .foregroundColor(.black) .padding(10) .background(Color.gray.opacity(0.1)) .cornerRadius(8) } Spacer() } .padding(.horizontal) } .padding(.top) } } .navigationTitle("Chatting with \(businessName)") .navigationBarTitleDisplayMode(.inline) .onAppear{ messengerLogic.fetchMessages(toId: userId) } } }
消息逻辑类
class MessengerLogic: ObservableObject { @Published var chatText = "" @Published var count = 0 @Published var errorMessage = "" @Published var chatMessages = [Message]() // 消息模型 @Published var recentMessages = [RecentMessage]() private var messageListener: ListenerRegistration? // 存储监听引用 func fetchMessages(toId: String) { // 先取消之前的监听,避免多个监听同时修改chatMessages messageListener?.remove() guard let fromId = FirebaseManager.shared.auth.currentUser?.uid else { return } messageListener = FirebaseManager.shared.firestore .collection("messages") .document(fromId) .collection(toId) .order(by: "timestamp") .addSnapshotListener { querySnapshot, error in if let error = error { DispatchQueue.main.async { self.errorMessage = "获取消息失败: \(error)" } return } DispatchQueue.main.async { self.chatMessages.removeAll() querySnapshot?.documents.forEach { document in if let message = Message(documentId: document.documentID, data: document.data()) { self.chatMessages.append(message) } } } } } // 可选:在对象销毁时取消监听,防止内存泄漏 deinit { messageListener?.remove() } }
问题原因分析
未取消旧监听:每次进入
MessengerMainView都会调用fetchMessages添加新的快照监听,但旧的监听没有被移除。切换不同聊天时,多个监听会同时修改chatMessages数组,导致数据源频繁异常变化,触发视图强制刷新,进而引发导航栈不稳定(自动返回根视图)。数据源标识不稳定:如果
Message或RecentMessage未正确实现Identifiable协议(或id属性不稳定),ForEach在数据源变化时无法正确追踪视图,可能导致视图重建异常,间接影响导航栈。
解决方案
管理监听生命周期:在
MessengerLogic中添加ListenerRegistration变量存储当前监听,每次调用fetchMessages前先取消旧监听,避免多个监听冲突。同时在对象销毁时取消监听,防止内存泄漏。确保模型实现Identifiable:检查
Message和RecentMessage模型,确保它们正确实现Identifiable协议,比如使用稳定的documentId作为id属性:
struct Message: Identifiable { let id: String let senderName: String let messageText: String let profileImage: String // 其他属性... init(documentId: String, data: [String: Any]) { self.id = documentId // 解析其他属性 } }
- 检查NavigationLink的使用:确保
MessengerInbox中的InboxRow包裹在NavigationLink内,避免因视图结构问题导致跳转异常。
内容的提问来源于stack exchange,提问作者Swink
相关产品推荐
相关产品推荐

