点击按钮时如何将Firebase数据传递到SwiftUI下一页?
问题解决
1. 页面跳转无效的原因及修复
你现在在按钮里直接初始化BetaInGameView的方式完全错误——SwiftUI的页面切换依赖导航容器(比如NavigationStack)或弹窗(sheet),不是直接创建视图实例就行。另外你还存在强制解包getAllGames返回值的风险,一旦没查到游戏会直接崩溃。
修复步骤:
- 在根视图(比如ContentView)中添加
NavigationStack,用navigationDestination绑定跳转逻辑 - 在ViewModel里添加可选的
currentGame状态变量,用@Published修饰,确保更新时能通知视图 - 按钮点击时,异步获取游戏后更新
currentGame,由导航栈自动触发跳转
2. 状态变量更新不触发视图刷新的原因及修复
你提到的CurrentGame未被检测到变化,核心是没用到SwiftUI的响应式状态管理机制:
- 若变量在ViewModel中,必须用
@Published修饰,且ViewModel要被视图用@StateObject或@ObservedObject持有观察 - 若变量在视图自身中,要用
@State修饰
修改后的完整代码示例
ViewModel部分
import FirebaseFirestore import FirebaseFirestoreSwift class JoinGameViewModel: ObservableObject { @Published var currentGame: Game? // @Published让视图感知变量变化 func getAllGames(gameCode: String) async throws -> Game? { guard let gameCodeInt = Int(gameCode) else { throw NSError(domain: "InvalidGameCode", code: 0, userInfo: [NSLocalizedDescriptionKey: "游戏码不是有效数字"]) } let querySnapshot = try await Firestore.firestore() .collection("activeGames") .whereField("gameCode", isEqualTo: gameCodeInt) .getDocuments() guard let gameDoc = querySnapshot.documents.first else { return nil // 未找到对应游戏,返回nil避免越界崩溃 } let game = try gameDoc.data(as: Game.self) print(game) return game } }
主视图(ContentView)部分
import SwiftUI struct ContentView: View { @StateObject private var joinViewModel = JoinGameViewModel() // @StateObject持有ViewModel @State private var gameCodeInput = "" var body: some View { NavigationStack { VStack { TextField("输入游戏码", text: $gameCodeInput) .textFieldStyle(.roundedBorder) .padding() Button("加入游戏") { Task { do { if let game = try await joinViewModel.getAllGames(gameCode: gameCodeInput) { joinViewModel.currentGame = game // 更新状态触发跳转 } else { // 可在此添加用户提示:未找到对应游戏 print("未找到该游戏码对应的游戏") } } catch { // 处理错误:比如游戏码格式错误、网络异常 print("获取游戏失败:\(error.localizedDescription)") } } } .buttonStyle(.borderedProminent) } .navigationDestination(item: $joinViewModel.currentGame) { game in BetaInGameView(game: game) // 绑定状态变量,自动跳转 } } } }
BetaInGameView保持不变
struct BetaInGameView: View { private let game: Game init(game: Game){ self.game=game } var body: some View { Text(String(game.gameCode)) .navigationTitle("游戏详情") } }
额外注意点
- 永远不要用
!强制解包Int(gameCode),用户输入非数字内容会直接崩溃,必须做可选绑定和错误处理 getAllGames中要判断查询结果是否为空,避免访问documents[0]时越界崩溃- 状态变量必须遵循SwiftUI响应式规则,
@Published+ObservableObject+@StateObject是标准组合
内容的提问来源于stack exchange,提问作者PokerBank
相关产品推荐
相关产品推荐

