模态转换后解除分配 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)
    



selectionScenecurrentRocketName 在加载到视图后立即传递给 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 被解除后运行回调函数/块?

当模态视图控制器被解除时如何调用函数

在模态视图控制器的解除动画时访问presentingViewController