模态转换后解除分配 SKScene
Posted
技术标签:
【中文标题】模态转换后解除分配 SKScene【英文标题】:Deallocate SKScene after modal transition 【发布时间】:2014-07-07 11:14:19 【问题描述】:我一直在使用 swift 在 sprite kit 中创建游戏,但遇到了问题。我有两个视图控制器,每个都有一个场景,一个以模态方式转换到另一个。这一切都在第一次完美运行,但是当我返回第一个视图控制器然后再次进入第二个时,我使用了双倍的内存。这给我的印象是没有任何东西被释放,但是每次我转换到场景时,对象都会被重新分配。我在仪器中运行该应用程序并得到了相同的结果。在下图中,我从一个场景移动到下一个场景,然后再次回到第一个场景,但它似乎重新分配了第一个场景,但没有清除任何内存。由于现在没有使用 dealloc 方法,我不知道如何解决这个问题。我会将代码发布到下面的第一个视图控制器,以便您查看。非常感谢。
import UIKit
import SpriteKit
class SelectionViewController: UIViewController
var selectionScene:SelectionScene?
var currentRocketName = ""
@IBOutlet var playButton: UIButton
override func viewDidLoad()
super.viewDidLoad()
if let selectionScene = SelectionScene.unarchiveFromFile("SelectionScene") as? SelectionScene
// Configure the view.
let skView = self.view as SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.multipleTouchEnabled = false
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
selectionScene.scaleMode = .ResizeFill
selectionScene.viewController = self
skView.presentScene(selectionScene)
NSNotificationCenter.defaultCenter().addObserver(selectionScene, selector: "spinnerChanged", name: "spinnerValueChanged", object: nil)
NSNotificationCenter.defaultCenter().addObserver(selectionScene, selector: "productBought", name: "ProductBought", object: nil);
NSNotificationCenter.defaultCenter().addObserver(selectionScene, selector: "manageErrorInPurchase", name: "ErrorOccured", object: nil)
override func shouldAutorotate() -> Bool
return true
override func viewDidAppear(animated: Bool)
@IBAction func playButtonPressed(sender: UIButton)
self.performSegueWithIdentifier("moveToGame", sender: nil)
override func prefersStatusBarHidden() -> Bool
return true
override func supportedInterfaceOrientations() -> Int
if UIDevice.currentDevice().userInterfaceIdiom == .Phone
return Int(UIInterfaceOrientationMask.AllButUpsideDown.toRaw())
else
return Int(UIInterfaceOrientationMask.All.toRaw())
override func didReceiveMemoryWarning()
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
override func viewDidUnload()
NSNotificationCenter.defaultCenter().removeObserver(selectionScene)
override func viewDidDisappear(animated: Bool)
NSNotificationCenter.defaultCenter().removeObserver(selectionScene)
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)
if segue.identifier == "moveToGame"
let destController = segue.destinationViewController as GameViewController
destController.rocketTexture = SKTexture(imageNamed: self.currentRocketName)
selectionScene
和 currentRocketName
在加载到视图后立即传递给 viewController
【问题讨论】:
【参考方案1】:我对 Swift 还不熟悉,所以我会用 Objective-C 给你例子。
为skView
创建一个IBOutlet
。当你要展示另一个 ViewController 时,从它的 superview 中删除 skView
并将其清除:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
// Need to deallocate GameScene (if game is not paused)
[self.skView removeFromSuperview];
self.skView = nil;
....
当 ViewController 正在加载时,不要忘记将 skView
添加回 ViewController 的视图:
if (!self.skView.window)
[self.view addSubview:self.skView];
要轻松检查SKScene
是否被释放,请添加此方法:
- (void)dealloc
NSLog(@"GAME SCENE DEALLOCATED");
【讨论】:
非常彻底的答案,除了不能与ios8和swift一起使用的dealloc方法之外,其他一切看起来都可以完美运行。 我还没见过 Swift :) @JackC 你可能想在 Swift 中使用deinit
而不是 dealloc
:developer.apple.com/library/prerelease/mac/documentation/Swift/…
好主意。我试试看。
@IgorTupitsyn 您的问题与此问题无关,您可以创建一个新问题吗?【参考方案2】:
我也有类似的问题。
事实证明,我通过将 SKScene 实例作为另一个类中的委托创建了一个强引用。在将 SKScene 类型或 UIView 类型的每个属性声明为弱后,我的问题得到了解决:
weak var skScene:SKScene!
【讨论】:
以上是关于模态转换后解除分配 SKScene的主要内容,如果未能解决你的问题,请参考以下文章
在自定义模式解除转换后,第一个视图控制器的生命周期方法不会被调用
UIViewController 在解除先前呈现的模态视图控制器后被释放
如何在没有委托的情况下以模态方式呈现 ViewController,然后在 ViewController 被解除后运行回调函数/块?