如何在TabBarController管理的两个ViewController间传递布尔值
披萨点击游戏的升级传值问题
我正在开发一款点击披萨赚钱的游戏,初始点击仅能获得1美元,购买升级后收益会提升。理论上点击1级升级按钮后,应让主游戏视图的单次点击收益变为5美元,但尝试了各种解决方案都无效。
我的GameViewController代码如下:
import UIKit class GameViewController: UIViewController { var wallet: Int = 0 var totalIncome: Int = 0 var level1UpgradeUsed: Bool = false @IBOutlet weak var pizzaButton: UIButton! @IBOutlet weak var labelWallet: UILabel! override func viewDidLoad() { super.viewDidLoad() print(level1UpgradeUsed) // Do any additional setup after loading the view. } @IBAction func pizzaClick(_ sender: Any) { let upgrades = UpgradesViewController() let level1UpgradeUsed = upgrades.level1used if level1UpgradeUsed == true { wallet = wallet + 4 } wallet = wallet + 1 labelWallet.text = ("$" + String(wallet)) } }
UpgradesViewController代码:
import UIKit class UpgradesViewController: UIViewController { public var level1used: Bool = false public var level2used: Bool = false public var level3used: Bool = false public var level4used: Bool = false var level5used: Bool = false @IBOutlet weak var buttonLevel1: UIButton! @IBOutlet weak var buttonLevel2: UIButton! @IBOutlet weak var buttonLevel3: UIButton! @IBOutlet weak var buttonLevel4: UIButton! @IBOutlet weak var buttonLevel5: UIButton! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let gameViewController = segue.destination as? GameViewController { gameViewController.level1UpgradeUsed = self.level1used } } @IBAction func Level1Click(_ sender: Any) { if level1used == false{ buttonLevel1.backgroundColor = UIColor.gray level1used = true } else { } } }
我猜测自己未正确利用TabBarController进行传值,但完全不知该如何操作。我是Swift新手,正在自学相关内容,麻烦帮忙解决。
问题原因
- 实例不共享:在
pizzaClick方法里你新建了UpgradesViewController实例,这是一个全新的对象,和TabBar里实际显示的升级页面不是同一个,所以永远拿不到用户点击升级后的true值。 - Segue传值无效:
prepare(for segue:)仅在通过Storyboard的segue跳转时生效,而TabBarController的页面切换不会触发这个方法,所以你的传值逻辑根本没起作用。
解决方案
方案1:通过TabBarController获取已存在的升级页面实例
直接从当前的TabBarController中找到已经加载的UpgradesViewController实例,而不是新建:
修改GameViewController的pizzaClick方法:
@IBAction func pizzaClick(_ sender: Any) { // 从TabBarController中获取UpgradesViewController实例 guard let tabBar = self.tabBarController, let upgradesVC = tabBar.viewControllers?.first(where: { $0 is UpgradesViewController }) as? UpgradesViewController else { return } // 根据升级状态增加收益 if upgradesVC.level1used { wallet += 4 } wallet += 1 labelWallet.text = "$\(wallet)" }
方案2:用单例统一管理游戏数据(推荐)
创建一个全局的游戏数据管理单例,所有页面都共享同一个数据源,避免页面间传值的麻烦,后续扩展功能也更方便:
- 创建
GameDataManager.swift文件:
import UIKit class GameDataManager { // 单例实例,全局唯一 static let shared = GameDataManager() // 私有初始化,禁止创建多个实例 private init() {} // 存储游戏数据 var wallet: Int = 0 var totalIncome: Int = 0 var level1used: Bool = false var level2used: Bool = false var level3used: Bool = false var level4used: Bool = false var level5used: Bool = false }
- 修改
GameViewController:
import UIKit class GameViewController: UIViewController { @IBOutlet weak var pizzaButton: UIButton! @IBOutlet weak var labelWallet: UILabel! override func viewDidLoad() { super.viewDidLoad() // 初始化显示当前钱包金额 labelWallet.text = "$\(GameDataManager.shared.wallet)" } @IBAction func pizzaClick(_ sender: Any) { let gameData = GameDataManager.shared // 应用升级收益 if gameData.level1used { gameData.wallet += 4 } gameData.wallet += 1 // 更新显示 labelWallet.text = "$\(gameData.wallet)" } }
- 修改
UpgradesViewController:
import UIKit class UpgradesViewController: UIViewController { @IBOutlet weak var buttonLevel1: UIButton! @IBOutlet weak var buttonLevel2: UIButton! @IBOutlet weak var buttonLevel3: UIButton! @IBOutlet weak var buttonLevel4: UIButton! @IBOutlet weak var buttonLevel5: UIButton! override func viewDidLoad() { super.viewDidLoad() // 页面加载时恢复按钮状态 let gameData = GameDataManager.shared buttonLevel1.backgroundColor = gameData.level1used ? .gray : .systemBlue // 其他升级按钮同理处理状态 } @IBAction func Level1Click(_ sender: Any) { let gameData = GameDataManager.shared if !gameData.level1used { buttonLevel1.backgroundColor = .gray gameData.level1used = true } } }
方案优势对比
- 方案1适合简单场景,快速解决当前传值问题,但后续如果添加更多升级或数据,会越来越繁琐。
- 方案2用单例统一管理数据,所有页面共享同一状态,后续添加进度保存(比如用
UserDefaults)、更多升级类型都会更轻松,是游戏开发中常用的模式。
内容的提问来源于stack exchange,提问作者Mason Ferrie
相关产品推荐
相关产品推荐

