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

SwiftUI按钮点击后无法按条件跳转至ChatScreen问题

问题描述

点击按钮时希望根据条件跳转至ChatScreen(),点击正确群组时控制台打印“group found”,但实际无法跳转,反而弹出弹窗。

代码示例
List(viewModel.danceGroups) { group in
                
    Button(action: {
            if authViewModel.authenticationState == .authenticated {
                check(groupId: group.id, userId: authViewModel.uid){ performed in
                    if performed{
                        goToChatScreen = true
                    }else {
                        showPopup = true
                    }
                }
            } else {
                showSignInSheet = true
            }
        }) {
            VStack(alignment: .leading) {
                    Text(group.groupName)
                        .bold()
                        .font(.title2)
                    Text(hoursAgo(from: TimeInterval(group.timestamp), from: group.isPermanent))
                        .font(.footnote)
                        .italic()
            }
        }
        .navigationDestination(isPresented: $goToChatScreen){
            ChatScreen(groupId: group.id)
        }
}


func check(groupId: String, userId: String, completion: @escaping (Bool) -> Void) {
    let database = Database.database().reference()
    
    let GroupsRef = //path
    
    GroupsRef.observeSingleEvent(of: .value) { snapshot in
        if snapshot.exists() {
            
            if let joinedDanceGroups = snapshot.value as? [String: Bool], joinedDanceGroups[groupId] == true {
                print("group found")
                completion(true)
            } else {
                print("group not found")
                completion(false)
            }
        } else {
            completion(false)
        }
    }
}
问题分析与解决方案

核心问题1:后台线程更新SwiftUI状态

Firebase的observeSingleEvent回调默认运行在后台队列,直接在回调里更新@State变量(goToChatScreen/showPopup)会导致状态更新无法被视图正确捕获,引发异常行为。

核心问题2:navigationDestination绑定逻辑错误

将navigationDestination附加在List的每个Button上,会导致多个导航目标绑定同一个布尔状态,状态变化时所有对应导航目标都会被触发,引发跳转冲突。

修复步骤:

  1. 切换主线程更新状态:在check函数的completion回调中,用DispatchQueue.main.async包裹状态更新代码,确保SwiftUI状态在主线程修改:
check(groupId: group.id, userId: authViewModel.uid){ performed in
    DispatchQueue.main.async {
        if performed{
            self.selectedGroupId = group.id
        }else {
            self.showPopup = true
        }
    }
}
  1. 调整导航目标位置:将navigationDestination从List的Button中移出,放在List外部(如NavigationStack的直接子视图位置),同时改用可选类型的selectedGroupId传递群组ID,替代布尔状态:
@State private var selectedGroupId: String?

// 放在List代码块之后
.navigationDestination(item: $selectedGroupId) { groupId in
    ChatScreen(groupId: groupId)
}
  1. 优化状态逻辑:用selectedGroupId替代goToChatScreen,通过可选值的有无控制跳转,逻辑更直观,避免布尔状态的歧义。

完整修复后代码片段

@State private var selectedGroupId: String?
@State private var showPopup = false
@State private var showSignInSheet = false

// ...

List(viewModel.danceGroups) { group in
    Button(action: {
        if authViewModel.authenticationState == .authenticated {
            check(groupId: group.id, userId: authViewModel.uid){ performed in
                DispatchQueue.main.async {
                    if performed {
                        selectedGroupId = group.id
                    } else {
                        showPopup = true
                    }
                }
            }
        } else {
            showSignInSheet = true
        }
    }) {
        VStack(alignment: .leading) {
            Text(group.groupName)
                .bold()
                .font(.title2)
            Text(hoursAgo(from: TimeInterval(group.timestamp), from: group.isPermanent))
                .font(.footnote)
                .italic()
        }
    }
}
.navigationDestination(item: $selectedGroupId) { groupId in
    ChatScreen(groupId: groupId)
}

额外验证点

  • 确认GroupsRef的路径配置正确,能正常读取用户加入的群组数据。
  • 检查authViewModel.uid是否为有效值,避免因用户ID为空导致查询错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:12:53