一尘不染

过渡到SpriteKit中的另一个SKScene后取消分配SKScene

swift

我有一个视图控制器,其中有三个skscenes作为子级。

当我从一个过渡到另一个时,旧的场景不会被释放。

我希望将其释放,就好像它从未出现过一样。

例:

当我第一次加载该应用程序时,只有1个场景可见(例如,它占用了100mb的内存),然后我过渡到另一个(100mb以上),然后是第三个(300mb内存)。

我最终将拥有300mb的内存,而我一直都希望拥有100mb。

我该如何实现?

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

阅读 142

收藏
2020-07-07

共1个答案

一尘不染

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

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

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.

2020-07-07