我正在使用SpriteKit为iOS制作游戏。
我有2个Viewcontrollers。一个是GameViewController,另一个是MenuViewController。我们分别称它们为A和B。
当玩家死亡时,会在GameScene.swift中调用一个函数,该函数向B启动模式“迷失” Segue。玩家可以在此处重新开始游戏或购买生命,并向A调用“ Back” Segue。
我需要取消每次调用segue时创建的其他视图。
问题是:我需要“ Lost” Segue将有关得分的数据发送到视图B,并且我需要“ Back” Segue将数据发送到View A,以了解玩家是否使用了生命。
我已经实现了所有这些。但是现在我需要找到如何消除旧的视图,这些视图会继续占用设备的内存,从而导致延迟和崩溃。
我已经搜索了几个小时。没有解决方案适合我的情况。
我找到的解决方案要么导致我的应用程序出现错误,要么不传递数据,要么不生成视图。
因为有很多,我不会在这里添加代码。但是我敢肯定,答案确实很简单,只是对于像我这样的初学者而言并非如此。
我认为可能的解决方案是从B到A轻松进行选择?
但是,轻松的搜寻是否传递数据?
而且,我没有找到关于如何使用放松顺序的答案。
我用尽了所有的可能性。堆栈交换是我最后的机会。
最佳答案
您绝对应该使用放松的顺序来返回到先前的viewController,否则,因为发现内存使用量增加,直到应用程序退出为止。
我根据您的描述创建了以下示例。它使用标准序列从GameViewController移至MenuViewController,并使用展开序列从MenuViewController移回到GameViewController。
GameViewController具有玩家骰子UIButton
,用于输入分数的UITextField
和用于显示生活的UILabel
。
MenuViewController具有用于显示分数的UILabel
,用于添加生命的Buy Life(购买生命)UIButton
和用于返回GameViewController的Restart UIButton
。
这是代码:
GameViewController.swift
import UIKit
class GameViewController: UIViewController {
@IBOutlet weak var scoreTextField: UITextField!
@IBOutlet weak var livesLabel: UILabel!
var lives = 3
func updateLivesLabel() {
livesLabel.text = "Lives: \(lives)"
}
override func viewDidLoad() {
super.viewDidLoad()
updateLivesLabel()
}
// This is the function that the unwind segue returns to.
// You can call it anything you want, but it has to be in
// the viewController you are returning to, it must be tagged
// with @IBAction and it must take a UIStoryboardSegue as its
// only parameter.
@IBAction func returnFromMenu(segue: UIStoryboardSegue) {
print("We're back in GameViewController")
// Update the lives label based upon the value passed in
// prepareForSegue from the MenuViewController.
updateLivesLabel()
}
@IBAction func goPlayerDies(sender: UIButton) {
lives--
self.performSegueWithIdentifier("Lost", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Lost" {
let destinationVC = segue.destinationViewController as! MenuViewController
destinationVC.score = Int(scoreTextField.text ?? "") ?? 0
destinationVC.lives = lives
}
}
}
MenuViewController.swift
import UIKit
class MenuViewController: UIViewController {
@IBOutlet weak var scoreLabel: UILabel!
var score = 0
var lives = 0
override func viewDidLoad() {
super.viewDidLoad()
scoreLabel.text = "Score: \(score)"
}
@IBAction func buyLife(sender: UIButton) {
lives++
}
@IBAction func goRestart(sender: UIButton) {
self.performSegueWithIdentifier("Back", sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "Back" {
let destinationVC = segue.destinationViewController as! GameViewController
destinationVC.lives = lives
}
}
}
这是连接正向序列以编程方式调用的方式:
按住Control键从ViewController图标拖动到MenuViewController:
从弹出窗口中选择“模态呈现”:
单击viewControllers之间的segue箭头,并在Attributes Inspector中为其指定标识符:
这是您如何以编程方式将展开的序列连接起来的方法:
按住Control键从ViewController图标拖动到Exit图标:
从弹出菜单中选择returnFromMenu:
单击“文档大纲”中的“展开”,然后在右侧的“属性”检查器中为其指定标识符“后退”:
替代答案
您可以手动显示和关闭viewController,而不是使用segues。您的应用程序的优点是MenuViewController将仅分配一次,并且在应用程序的生命周期内将持续存在。相同的viewController将被反复显示和关闭,但是不会被释放,我怀疑这会导致您的崩溃。
GameViewController将是由Storyboard创建的initialViewController。 MenuViewController将被加载到GameViewController的
viewDidLoad
中。为了使这项工作有效,您需要向MenuViewController添加一个标识符,以便可以通过名称实例化它。单击情节提要中的MenuViewController,然后在身份检查器中设置其情节提要ID:
这是代码。请注意,所有关于segue的提及都已消失。注意如何使用
viewWillAppear
更新viewControllers。GameViewController.swift
import UIKit
class GameViewController: UIViewController {
@IBOutlet weak var scoreTextField: UITextField!
@IBOutlet weak var livesLabel: UILabel!
var menuViewController: MenuViewController?
var lives = 3
func updateLivesLabel() {
livesLabel.text = "Lives: \(lives)"
}
override func viewDidLoad() {
super.viewDidLoad()
menuViewController = self.storyboard!.instantiateViewControllerWithIdentifier("MenuViewController") as? MenuViewController
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
updateLivesLabel()
}
@IBAction func goPlayerDies(sender: UIButton) {
lives--
menuViewController?.score = Int(scoreTextField.text ?? "") ?? 0
menuViewController?.lives = lives
self.presentViewController(menuViewController!, animated: true, completion: nil)
}
}
MenuViewController.swift
import UIKit
class MenuViewController: UIViewController {
@IBOutlet weak var scoreLabel: UILabel!
var score = 0
var lives = 0
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
scoreLabel.text = "Score: \(score)"
}
@IBAction func buyLife(sender: UIButton) {
lives++
}
@IBAction func goRestart(sender: UIButton) {
let destinationVC = self.presentingViewController as! GameViewController
destinationVC.lives = lives
self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}