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

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()
    }
}

问题原因分析

  1. 未取消旧监听:每次进入MessengerMainView都会调用fetchMessages添加新的快照监听,但旧的监听没有被移除。切换不同聊天时,多个监听会同时修改chatMessages数组,导致数据源频繁异常变化,触发视图强制刷新,进而引发导航栈不稳定(自动返回根视图)。

  2. 数据源标识不稳定:如果Message或RecentMessage未正确实现Identifiable协议(或id属性不稳定),ForEach在数据源变化时无法正确追踪视图,可能导致视图重建异常,间接影响导航栈。

解决方案

  1. 管理监听生命周期:在MessengerLogic中添加ListenerRegistration变量存储当前监听,每次调用fetchMessages前先取消旧监听,避免多个监听冲突。同时在对象销毁时取消监听,防止内存泄漏。

  2. 确保模型实现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
        // 解析其他属性
    }
}
  1. 检查NavigationLink的使用:确保MessengerInbox中的InboxRow包裹在NavigationLink内,避免因视图结构问题导致跳转异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:58:10