Deallocate SKScene after transition to another SKScene in SpriteKit

故事扮演 提交于 2019-11-28 17:59:17
ZeMoon

A similar problem was faced by the person who asked this question.

When asked whether he was able to solve it, they said:

Yes, I did, there wasn't anything I could do about it from the scene or Sprite Kit for that matter, I simply needed to remove the scene and the view containing it completely from the parent view, cut all its bonds to the other parts of the system, in order for the memory to be deallocated as well.

You should use separate views for each of your scene and transition between these views. You can follow these steps to make it look natural:

1 - At the point you want to transition from one scene to the other, take a snapshot of the scene using the following code:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Then, add this image as a subview of the SKView of the current scene, and remove the scene.

2 - Initialise the new scene on another view, and transition between the two views using UIView animation.

3 - Remove the first view from it's superview.

I am just starting out with SpriteKit in Swift and I had the same problem: My "intro" scene was playing some music that I wanted to stop after transitioning to the main menu scene, and I figured deinit would be a good place to put the AVAudioPlayer.stop call in, but the deinitializer was never being called.

After some looking around I learned that it may be because of some strong references to the scene, so I changed

let s = StartupScene(size: skView.bounds.size)
skView.presentScene(s)

to

skView.presentScene(StartupScene(size: skView.bounds.size))

in my GameViewController:UIViewController, and

let s = MainMenuScene(size: self.size)
let t = SKTransition.crossFadeWithDuration(1)
self.scene.view.presentScene(s, transition: t)

to

self.scene.view.presentScene(MainMenuScene(size: self.size), transition: SKTransition.crossFadeWithDuration(1))

in the scene that I wanted to deallocate, and it worked! After the transition was complete the deinit method got called.

Hopefully someone more experienced can edit this answer to better explain what exactly took place here.

EDIT: My previous idea about an NSTimer was irrelevant

To make sure this is an issue isolated to this scene, override the dealloc methods of all scenes you might have (including this one) like this:

 -(void)dealloc {
  NSLog(@"Dealloc <scene name>");
 }

Look at your other scene transitions, see if they deallocate properly. Find the differences between these scenes. This will help you see if it's an isolated issue or a bigger problem. Once you have the problem fixed be sure to comment out or remove the dealloc method as it is overriding the one that actually deallocates the memory. Hopefully this helps!

Bogdan

There's nothing wrong with SKScene or SKView, as long as I can see. Make sure the scene instance is not strongly reference anywhere else, especially inside a block. Blocks are highly probable to be ignored.

More about weak reference inside a block: https://stackoverflow.com/a/17105368/571489

As far as I see, you do have a block strongly referencing the scene instance:

[SKTexture preloadTextures:to_preload withCompletionHandler:^{
    [self fadeRemove:masterOverlay];
    [self initialize];
}];
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!