需要在 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 segue 从 MenuViewController 回到 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)
}
}
我正在使用 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 segue 从 MenuViewController 回到 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)
}
}