在转换到SpriteKit中的另一个SKScene之后取消分配SKScene

我有一个视图控制器,有三个孩子的skscenes。

当我从一个转换到另一个时,旧的skscene不会被释放。

我希望它被释放,就好像它从来没有。

例:

当我第一次加载应用程序,只有1 skscene可见(说它占用100MB的内存),然后我转移到另一个(100MB多),然后第三个(300MB的内存)。

我最终会有300MB的内存,我想一直有100个。

我怎样才能做到这一点?

My view controller: // // ViewController.m // Paddle Jumper // // Created by Chance Daniel on 1/18/14. // Copyright (c) 2014 Max Hudson. All rights reserved. // #import "Flurry.h" #import "ViewController.h" #import "startViewController.h" @implementation ViewController{ BOOL sceneSetUp; } - (void)viewWillLayoutSubviews { if(!sceneSetUp){ [super viewWillLayoutSubviews]; // Configure the view. SKView * skView = (SKView *)self.view; //skView.showsFPS = YES; //skView.showsNodeCount = YES; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; if([[defaults objectForKey:@"firstTime"] intValue] != 1){ [defaults setObject:[NSNumber numberWithInt:1] forKey:@"firstTime"]; [defaults setObject:@"ggr" forKey:@"skinSelected"]; [defaults setObject:[NSNumber numberWithInt:2] forKey:@"ggrOwned"]; [defaults setObject:[NSNumber numberWithInt:5000] forKey:@"gona"]; [defaults setObject:[NSNumber numberWithInt:1500] forKey:@"points"]; [defaults setObject:[NSNumber numberWithInt:7] forKey:@"livesLeftValue"]; [defaults setObject:[NSNumber numberWithInt:3] forKey:@"shieldsLeftValue"]; [defaults setObject:[NSNumber numberWithInt:2] forKey:@"lvlTwoLeftValue"]; [defaults setObject:[NSNumber numberWithInt:0] forKey:@"lvlThreeLeftValue"]; } if(![defaults objectForKey:@"tut_game1"]){ [defaults setObject:[NSNumber numberWithInt:1] forKey:@"tut_game1"]; [defaults setObject:[NSNumber numberWithInt:1] forKey:@"tut_store"]; [defaults setObject:[NSNumber numberWithInt:1] forKey:@"tut_daily"]; } [defaults synchronize]; // Create and configure the scene. SKScene * startScene = [StartViewController sceneWithSize:skView.bounds.size]; startScene.scaleMode = SKSceneScaleModeAspectFill; // Present the scene. [skView presentScene:startScene]; //[skView presentScene:scene]; sceneSetUp = YES; } } -(void) switchScene{ } - (BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { return UIInterfaceOrientationMaskAllButUpsideDown; } else { return UIInterfaceOrientationMaskAll; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Release any cached data, images, etc that aren't in use. } @end An SKScene that won't release: // // SettingsSKScene.m // Paddle Jumper // // Created by Max Hudson on 3/15/14. // Copyright (c) 2014 Max Hudson. All rights reserved. // #import "SettingsSKScene.h" #import "gameViewController.h" #import "StoreScene.h" @interface SettingsSKScene (){ SKSpriteNode *bg; SKSpriteNode *masterOverlay; SKSpriteNode *wbox; SKSpriteNode *gamecenter; SKSpriteNode *max; SKSpriteNode *chance; SKSpriteNode *bryce; SKSpriteNode *home; SKSpriteNode *play; SKSpriteNode *chance_link; SKSpriteNode *max_link; SKSpriteNode *bryce_link; SKSpriteNode *fbButton; SKSpriteNode *fbToggleYes; SKSpriteNode *fbToggleNo; SKLabelNode *story1; SKLabelNode *story2; SKLabelNode *story3; SKLabelNode *chance_name; SKLabelNode *max_name; SKLabelNode *bryce_name; SKLabelNode *chance_role; SKLabelNode *max_role; SKLabelNode *bryce_role; SKLabelNode *chance_handle; SKLabelNode *max_handle; SKLabelNode *bryce_handle; SKTexture *bg_texture; SKTexture *gamecenter_texture; SKTexture *wbox_texture; SKTexture *max_texture; SKTexture *chance_texture; SKTexture *bryce_texture; SKTexture *home_texture; SKTexture *play_texture; SKTexture *fb_texture; SKTexture *toggle_yes_texture; SKTexture *toggle_no_texture; } @end @implementation SettingsSKScene -(id) initWithSize:(CGSize)size{ if(self = [super initWithSize:size]){ masterOverlay = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:self.frame.size]; masterOverlay.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); [self addChild:masterOverlay]; bg_texture = [SKTexture textureWithImageNamed:@"settings_bg"]; wbox_texture = [SKTexture textureWithImageNamed:@"white_rect_bg"]; gamecenter_texture = [SKTexture textureWithImageNamed:@"gc"]; max_texture = [SKTexture textureWithImageNamed:@"max"]; chance_texture = [SKTexture textureWithImageNamed:@"chance"]; bryce_texture = [SKTexture textureWithImageNamed:@"bryce"]; home_texture = [SKTexture textureWithImageNamed:@"home_light"]; play_texture = [SKTexture textureWithImageNamed:@"play_light"]; fb_texture = [SKTexture textureWithImageNamed:@"fb_light"]; toggle_yes_texture = [SKTexture textureWithImageNamed:@"toggle_yes"]; toggle_no_texture = [SKTexture textureWithImageNamed:@"toggle_no"]; NSArray *to_preload = @[bg_texture, wbox_texture, gamecenter_texture, max_texture, chance_texture, bryce_texture, home_texture, play_texture, fb_texture, toggle_yes_texture, toggle_no_texture]; [SKTexture preloadTextures:to_preload withCompletionHandler:^{ [self fadeRemove:masterOverlay]; [self initialize]; }]; } return self; } -(void) fadeRemove: (SKNode *) node{ double duration = arc4random() % 10; duration *= 0.05; SKAction *fadeOut = [SKAction fadeOutWithDuration:0.1+duration]; SKAction *remove = [SKAction runBlock:^{ [node removeFromParent]; }]; [node runAction:[SKAction sequence:@[fadeOut, remove]]]; } -(void) initialize{ bg = [SKSpriteNode spriteNodeWithTexture:bg_texture]; bg.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); bg.zPosition = 0; wbox = [SKSpriteNode spriteNodeWithTexture:wbox_texture]; wbox.position = CGPointMake(self.frame.size.width/2, 70); wbox.alpha = 0.8; wbox.zPosition = 2; gamecenter = [SKSpriteNode spriteNodeWithTexture:gamecenter_texture]; gamecenter.position = CGPointMake(self.frame.size.width/2 + 100, self.frame.size.height/2-2); gamecenter.name = @"gc"; gamecenter.zPosition = 2; fbButton = [SKSpriteNode spriteNodeWithTexture:fb_texture]; fbButton.size = CGSizeMake(36, 36); fbButton.position = CGPointMake(self.frame.size.width/2 - 115, self.frame.size.height/2-2); fbButton.name = @"fb"; fbButton.zPosition = 2; fbToggleNo = [SKSpriteNode spriteNodeWithTexture:toggle_no_texture]; fbToggleNo.position = CGPointMake(self.frame.size.width/2 - 50, self.frame.size.height/2-2); fbToggleNo.size = CGSizeMake(fbToggleNo.size.width/3, fbToggleNo.size.height/3); fbToggleNo.name = @"fbno"; fbToggleNo.zPosition = 2; fbToggleYes = [SKSpriteNode spriteNodeWithTexture:toggle_yes_texture]; fbToggleYes.position = CGPointMake(self.frame.size.width/2 - 70, self.frame.size.height/2-2); fbToggleYes.name = @"fbyes"; fbToggleYes.zPosition = 2; int hpBuffer = 40; int hpZ = 2; home = [SKSpriteNode spriteNodeWithTexture:home_texture]; home.position = CGPointMake(hpBuffer, self.frame.size.height - hpBuffer); home.zPosition = hpZ; home.name = @"home"; play = [SKSpriteNode spriteNodeWithTexture:play_texture]; play.position = CGPointMake(self.frame.size.width - hpBuffer, self.frame.size.height - hpBuffer); play.zPosition = hpZ; play.name = @"play"; [self addChild:bg]; [self addChild:wbox]; [self addChild:gamecenter]; [self addChild:home]; [self addChild:play]; [self addChild:fbButton]; [self addChild:fbToggleNo]; [self addCredits]; [self addStory]; } -(void) addCredits{ /* images */ int cmbZ = wbox.zPosition + 1; int cmbY = wbox.position.y; int cmbXUnit = 132; int cmbX = self.frame.size.width/2 - (3*cmbXUnit)/2 + 20; int cmbWidth = 40; chance = [SKSpriteNode spriteNodeWithTexture:chance_texture]; max = [SKSpriteNode spriteNodeWithTexture:max_texture]; bryce = [SKSpriteNode spriteNodeWithTexture:bryce_texture]; chance.zPosition = cmbZ; max.zPosition = cmbZ; bryce.zPosition = cmbZ; chance.position = CGPointMake(cmbX+cmbXUnit*0, cmbY+3); max.position = CGPointMake(cmbX+cmbXUnit*1 + 10, cmbY); bryce.position = CGPointMake(cmbX+cmbXUnit*2 + 10, cmbY+5); chance.size = CGSizeMake(cmbWidth, (chance.size.height/chance.size.width)*cmbWidth); max.size = CGSizeMake(cmbWidth, (max.size.height/max.size.width)*cmbWidth); bryce.size = CGSizeMake(cmbWidth, (bryce.size.height/bryce.size.width)*cmbWidth); [self addChild:chance]; [self addChild:max]; [self addChild:bryce]; /* names */ int cmb_nameXUnit = 30; int cmb_nameY = wbox.position.y - 10; int cmb_nameFontSize = 18; chance_name = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; max_name = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; bryce_name = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; chance_name.text = @"Chance Daniel"; max_name.text = @"Max Hudson"; bryce_name.text = @"Bryce Daniel"; chance_name.fontColor = [SKColor blackColor]; max_name.fontColor = [SKColor blackColor]; bryce_name.fontColor = [SKColor blackColor]; chance_name.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft; max_name.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft; bryce_name.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft; chance_name.position = CGPointMake(chance.position.x + cmb_nameXUnit, cmb_nameY); max_name.position = CGPointMake(max.position.x + cmb_nameXUnit, cmb_nameY); bryce_name.position = CGPointMake(bryce.position.x + cmb_nameXUnit, cmb_nameY); chance_name.fontSize = cmb_nameFontSize; max_name.fontSize = cmb_nameFontSize; bryce_name.fontSize = cmb_nameFontSize; chance_name.zPosition = cmbZ; max_name.zPosition = cmbZ; bryce_name.zPosition = cmbZ; [self addChild:chance_name]; [self addChild:max_name]; [self addChild:bryce_name]; /* roles */ int cmb_roleY = wbox.position.y - 25; int cmb_roleFontSize = 11; chance_role = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; max_role = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; bryce_role = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; chance_role.text = @"Programmer"; max_role.text = @"Programmer"; bryce_role.text = @"Graphic Designer"; chance_role.fontColor = [SKColor darkGrayColor]; max_role.fontColor = [SKColor darkGrayColor]; bryce_role.fontColor = [SKColor darkGrayColor]; chance_role.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft; max_role.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft; bryce_role.horizontalAlignmentMode = SKLabelHorizontalAlignmentModeLeft; chance_role.position = CGPointMake(chance.position.x + cmb_nameXUnit + 19, cmb_roleY); max_role.position = CGPointMake(max.position.x + cmb_nameXUnit + 12, cmb_roleY); bryce_role.position = CGPointMake(bryce.position.x + cmb_nameXUnit + 6, cmb_roleY); chance_role.fontSize = cmb_roleFontSize; max_role.fontSize = cmb_roleFontSize; bryce_role.fontSize = cmb_roleFontSize; chance_role.zPosition = cmbZ; max_role.zPosition = cmbZ; bryce_role.zPosition = cmbZ; [self addChild:chance_role]; [self addChild:max_role]; [self addChild:bryce_role]; /* twitter handles */ int cmb_handY = wbox.position.y - 40; int cmb_handFontSize = 10; chance_handle = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; max_handle = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; bryce_handle = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; chance_handle.text = @"@ChanceOfThat"; max_handle.text = @"@max_hud"; bryce_handle.text = @"@BryceOfLife"; chance_handle.fontColor = [SKColor darkGrayColor]; max_handle.fontColor = [SKColor darkGrayColor]; bryce_handle.fontColor = [SKColor darkGrayColor]; chance_handle.position = CGPointMake(chance.position.x, cmb_handY); max_handle.position = CGPointMake(max.position.x, cmb_handY); bryce_handle.position = CGPointMake(bryce.position.x, cmb_handY); chance_handle.fontSize = cmb_handFontSize; max_handle.fontSize = cmb_handFontSize; bryce_handle.fontSize = cmb_handFontSize; chance_handle.zPosition = cmbZ; max_handle.zPosition = cmbZ; bryce_handle.zPosition = cmbZ; [self addChild:chance_handle]; [self addChild:max_handle]; [self addChild:bryce_handle]; /* touchzones */ CGSize cmdL_size = CGSizeMake(120, 70); SKColor *cmdL_color = [SKColor clearColor]; int cmdLZ = 3; int cmdLX = cmbX + 40; chance_link = [SKSpriteNode spriteNodeWithColor:cmdL_color size:cmdL_size]; max_link = [SKSpriteNode spriteNodeWithColor:cmdL_color size:cmdL_size]; bryce_link = [SKSpriteNode spriteNodeWithColor:cmdL_color size:cmdL_size]; chance_link.position = CGPointMake(cmdLX+cmbXUnit*0, cmbY); max_link.position = CGPointMake(cmdLX+cmbXUnit*1 + 10, cmbY); bryce_link.position = CGPointMake(cmdLX+cmbXUnit*2 + 10, cmbY); chance_link.zPosition = cmdLZ; max_link.zPosition = cmdLZ; bryce_link.zPosition = cmdLZ; chance_link.name = @"c_handle"; max_link.name = @"m_handle"; bryce_link.name = @"b_handle"; [self addChild:chance_link]; [self addChild:max_link]; [self addChild:bryce_link]; } -(void) addStory{ int stX = self.frame.size.width/2; int stZ = 2; SKColor *stColor = [SKColor whiteColor]; story1 = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; story2 = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; story3 = [SKLabelNode labelNodeWithFontNamed:@"BebasNeue"]; story1.text = @"Gon"; story2.text = @"Help Gon-Gon and his friends get"; story3.text = @"Back to the time they came from!"; story1.fontColor = stColor; story2.fontColor = stColor; story3.fontColor = stColor; story1.zPosition = stZ; story2.zPosition = stZ; story3.zPosition = stZ; story1.position = CGPointMake(stX, self.frame.size.height - 55); story1.fontSize = 50; story2.position = CGPointMake(stX, self.frame.size.height - 95); story2.fontSize = 30; story3.position = CGPointMake(stX, self.frame.size.height - 120); story3.fontSize = 20; [self addChild:story1]; [self addChild:story2]; [self addChild:story3]; } -(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ UITouch *touchUI = [touches anyObject]; CGPoint touchPoint = [touchUI locationInNode:self]; SKNode *touchNode = [self nodeAtPoint:touchPoint]; if([touchNode.name isEqualToString:@"home"]){ StartViewController *svc = [[StartViewController alloc] initWithSize:self.size]; SKTransition *fade = [SKTransition fadeWithColor :[SKColor blackColor] duration:0.4]; [self.view presentScene:svc transition:fade]; } if([touchNode.name isEqualToString:@"play"]){ gameViewController *gvc = [[gameViewController alloc] initWithSize:self.size]; SKTransition *fade = [SKTransition fadeWithColor :[SKColor blackColor] duration:0.4]; [self.view presentScene:gvc transition:fade]; } if([touchNode.name isEqualToString:@"gc"]){ NSDictionary * dict = [[NSDictionary alloc]initWithObjectsAndKeys:[NSNumber numberWithBool:1], @"showGC", nil]; [[NSNotificationCenter defaultCenter]postNotificationName:@"kNotificationUpdateBannerView" object:self userInfo:dict]; } if([touchNode.name isEqualToString:@"c_handle"]){ NSURL *urlApp = [NSURL URLWithString: [NSString stringWithFormat:@"%@", @"twitter:///user?screen_name=ChanceOfThat"]]; int worked = [[UIApplication sharedApplication] openURL:urlApp]; if(!worked){ NSURL *urlApp = [NSURL URLWithString: [NSString stringWithFormat:@"%@", @"https://twitter.com/#!/ChanceOfThat"]]; [[UIApplication sharedApplication] openURL:urlApp]; } } if([touchNode.name isEqualToString:@"m_handle"]){ NSURL *urlApp = [NSURL URLWithString: [NSString stringWithFormat:@"%@", @"twitter:///user?screen_name=max_hud"]]; int worked = [[UIApplication sharedApplication] openURL:urlApp]; if(!worked){ NSURL *urlApp = [NSURL URLWithString: [NSString stringWithFormat:@"%@", @"https://twitter.com/#!/max_hud"]]; [[UIApplication sharedApplication] openURL:urlApp]; } } if([touchNode.name isEqualToString:@"b_handle"]){ NSURL *urlApp = [NSURL URLWithString: [NSString stringWithFormat:@"%@", @"twitter:///user?screen_name=BryceOfLife"]]; int worked = [[UIApplication sharedApplication] openURL:urlApp]; if(!worked){ NSURL *urlApp = [NSURL URLWithString: [NSString stringWithFormat:@"%@", @"https://twitter.com/#!/BryceOfLife"]]; [[UIApplication sharedApplication] openURL:urlApp]; } } } @end 

提出这个问题的人也面临类似的问题。

当被问及他是否能够解决这个问题时,他们说:

是的,我做了,从现场或Sprite Kit中我没有办法做到这一点,我只需要从父视图中完全删除包含它的场景和视图,将它的所有绑定切换到另一个系统的一部分,以便内存也被释放。

您应该为每个场景使用不同的视图,并在这些视图之间进行转换。 您可以按照以下步骤使其看起来很自然:

1 – 在要从一个场景转换到另一个场景的位置,使用以下代码拍摄场景快照:

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

然后,添加此图像作为当前场景的SKView的子视图,并删除场景。

2 – 在另一个视图上初始化新场景,并使用UIViewanimation在两个视图之间切换。

3 – 从它的超级视图中删除第一个视图。

我刚开始在Swift中使用SpriteKit,而且我遇到了同样的问题:我的“intro”场景正在播放一些我想在转换到主菜单场景后停止播放的音乐,而我认为这将是一个放置AVAudioPlayer.stop调用,但deinitializer从未被调用。

经过一番四处观察,我了解到,这可能是由于一些强烈的现场引用,所以我改变了

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

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

在我的GameViewController:UIViewController和

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

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

在我想要释放的场景中,它起作用了! 转换完成后,deinit方法被调用。

希望更有经验的人可以编辑这个答案,以更好地解释这里发生了什么。

编辑:我以前的关于NSTimer的想法是无关紧要的

为了确保这是一个与这个场景相关的问题,可以像下面这样覆盖你可能拥有的所有场景(包括这个场景)的dealloc方法:

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

看看你的其他场景转换,看看他们是否正确释放。 找出这些场景之间的差异。 这将帮助你看看这是一个孤立的问题还是一个更大的问题。 一旦你解决了这个问题,一定要注释掉或删除dealloc方法,因为它重写了实际释放内存的方法。 希望这有助于!

SKScene或SKView没有问题,只要我能看到。 确保场景实例在其他地方不强烈引用,特别是在块内部。 块很有可能被忽略。

有关块内部弱引用的更多信息: https : //stackoverflow.com/a/17105368/571489

据我所知,你有一个块强烈引用场景实例:

 [SKTexture preloadTextures:to_preload withCompletionHandler:^{ [self fadeRemove:masterOverlay]; [self initialize]; }]; 
Interesting Posts