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

点击按钮时如何将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 06:23:28