需要在 Modal Segues 之后释放内存,但我需要我的两个 Segues 将数据从 A 传递到 B 并将数据传递到 A

Need to free memory after Modal Segues, but I need both my Segues to pass data from A to B and B to A

我正在使用 SpriteKit 为 iOS 制作游戏。

我有 2 个视图控制器。一个是 GameViewController,另一个是 MenuViewController。我们分别称他们为A和B。

当玩家死亡时,在 GameScene.swift 中调用一个函数来启动模式 "Lost" Segue 到 B。在那里,玩家可以重新开始游戏或购买生命和 "Back" Segue 被调用到 A.

我需要关闭每次调用 segue 时创建的额外视图。

问题是:我需要 "Lost" Segue 将关于分数的数据发送到视图 B,我需要 "Back" Segue 将关于玩家是否使用了 a 的数据发送到视图 A生活。

这些我都实现了。但现在我需要找到如何消除不断消耗设备内存的旧视图,从而导致延迟和崩溃。

我用谷歌搜索了好几个小时。没有适合我情况的解决方案。

我找到的解决方案要么导致我的应用出现错误,要么无法传递数据,要么无法生成视图。

我不会在这里添加代码,因为有很多。但我相信答案其实很简单,只是不适合像我这样的初学者。

我认为可能的解决方案是从 B 到 A 的展开转场?

但是 unwind segues 会传递数据吗?

此外,我找不到关于如何使用 unwind segue 的答案。

我用尽了所有的可能性。 Stack Exchange 是我最后的机会。

你绝对应该使用 unwind segue 到 return 到之前的 viewController,否则你会发现你的内存使用量增加直到你的应用程序退出.

我根据您的描述创建了以下示例。它使用标准 segue 从 GameViewController 移动到 MenuViewController 并使用 unwind segueMenuViewController 回到 GameViewController.

游戏ViewController有一个玩家死亡UIButton,一个UITextField进入一个分数,还有一个UILabel用来显示生命。

菜单ViewController有一个UILabel用来显示分数,一个买一条命UIButton 用于增加生命,重启 UIButton 用于return进入游戏ViewController .

代码如下:

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图标拖到菜单ViewController:


Select 模态显示 从弹出窗口:


单击 viewController 之间的 segue 箭头 并在 Attributes Inspector 中为其指定标识符:


这就是如何连接 unwind segue 以编程方式调用:

控制-从ViewController图标拖到退出图标:


从弹出菜单中选择returnFromMenu:


单击 文档大纲 中的 Unwind Segue 并为其指定标识符 "Back"在右边的Attributes Inspector中:


备选答案

您可以手动显示和关闭 viewController,而不是使用 segues。您的应用程序的优点是 MenuViewController 只会分配一次,并且会在应用程序的整个生命周期内持续存在。同样的 viewController 将反复出现和关闭,但它不会被释放,我怀疑这会导致您的崩溃。

游戏ViewController将是故事板创建的初始ViewController。 菜单ViewController 将加载到 游戏ViewController.

viewDidLoad

要使其工作,您需要向 MenuViewController 添加一个标识符,以便它可以按名称实例化。单击 Storyboard 中的 MenuViewController 并在 Identity Inspector 中设置其 Storyboard ID:


这是代码。请注意,所有提到的 segues 都消失了。请注意 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)
    }
}