Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 转换到SpriteKit中的另一个SKScene后取消分配SKScene_Ios_Objective C_Swift_Sprite Kit_Deinit - Fatal编程技术网

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

Ios 转换到SpriteKit中的另一个SKScene后取消分配SKScene,ios,objective-c,swift,sprite-kit,deinit,Ios,Objective C,Swift,Sprite Kit,Deinit,我有一个视图控制器,作为孩子有三个场景 当我从一个场景过渡到另一个场景时,旧场景不会被取消分配 我希望它能像从未有过一样被释放 例如: 当我第一次加载应用程序时,只有一个场景是可见的(比如说它占用了100mb内存),然后我转换到另一个(多100mb),然后是第三个(300mb内存) 我最终会有300mb的内存,我希望在任何时候都有100个 我怎样才能做到这一点 My view controller: // // ViewController.m // Paddle Jumper // /

我有一个视图控制器,作为孩子有三个场景

当我从一个场景过渡到另一个场景时,旧场景不会被取消分配

我希望它能像从未有过一样被释放

例如:

当我第一次加载应用程序时,只有一个场景是可见的(比如说它占用了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

编辑:我之前关于NSTimer的想法与此无关

要确保此问题与此场景无关,请覆盖所有场景(包括此场景)的dealloc方法,如下所示:

 -(void)dealloc {
  NSLog(@"Dealloc <scene name>");
 }
-(无效)解除锁定{
NSLog(@“dealoc”);
}

查看其他场景变换,看看它们是否正确释放。找出这些场景之间的差异。这将帮助您了解这是一个孤立的问题还是一个更大的问题。一旦问题得到解决,请确保注释掉或删除dealloc方法,因为它将覆盖实际释放内存的方法。希望这有帮助

问这个问题的人也面临着类似的问题

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

是的,我做了,从现场看我无能为力 或者精灵套件,我只需要移除场景并 从父视图中完全包含它的视图,剪切其所有 连接到系统的其他部分,以便存储 也被解除了

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

1-在要从一个场景过渡到另一个场景时,使用以下代码拍摄场景快照:

UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, scale);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
然后,将此图像添加为当前场景的SKView的子视图,并删除该场景

2-在另一个视图上初始化新场景,并使用UIView动画在两个视图之间转换


3-从superview中删除第一个视图。

我刚开始在Swift中使用SpriteKit,我遇到了同样的问题:我的介绍场景在过渡到主菜单场景后播放了一些我想停止的音乐,我认为
deinit
将是放置
AVAudioPlayer.stop()
调用的好地方,但是,
deinit
从未被调用

环顾四周后,我了解到这可能是因为一些对场景的强烈引用,因此在我的
GameViewController:UIViewController
子类中,我更改了以下代码:

let intro = IntroScene(size: skView.bounds.size)
skView.presentScene(intro)

在介绍场景中,我想被解除分配,我改变了

let mainMenu  = MainMenuScene(size: self.size)
let crossFade = SKTransition.crossFadeWithDuration(1)

self.scene.view.presentScene(mainMenu, transition: crossFade)

成功了!转换完成后,调用了
deinit
方法


我假设传出场景没有被取消初始化,因为有变量包含对它的引用。

只要我能看到,SKScene或SKView没有问题。确保场景实例不在其他任何位置(尤其是块内部)强引用。块极有可能被忽略

有关块内弱参照的详细信息:

就我所见,您确实有一个强烈引用场景实例的块:

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

2019年12月/Swift 5

更新:

我的布局:

我有一个单视图控制器,其中包含两个SKViews,每个SKViews都有自己独特的SKScene,同时显示。一个SKView及其SKScene是主要的超世界,玩家角色在这里被渲染、控制、NPC渲染、摄像机跟踪、整个shebang等,另一个SKView及其SKScene显示超世界的迷你地图。 你可以想象,还有相当多的SKSpriteNode&它们中的很多总是有某种SKAction/动画不停地运行(例如摇摆的树)。我的SKScenes甚至包含它们自己的数组,指向特定的SKSpriteNodes组,例如角色节点、建筑节点、树节点。这是为了快速访问和方便。 另外,我还有一些单例,它们要么包含一系列纹理,要么包含角色模型,等等。。它们作为快速数据访问的优化而保留,而不是每次需要时从光盘读取/访问存储。 视图控制器中甚至有用于游戏UI的UIKit元素。 许多其他对象,例如,我的模型,其中包含角色、建筑、整个游戏会话的数据,都有一些代理指向某人。除此之外,代码库是巨大的

在调试会话中观察内存后,我发现确保不保留任何内容的sure fire方法是绝对确保以下内容:

内存处理:

  • 为场景演示传入nil并将skview的属性/指针也设置为nil
  • 删除所有视图控制器主视图子视图
  • 绝对设置每个代表你必须为零
  • 如果您碰巧有任何观察者,请删除所有观察者
  • 只要有指向所创建对象的数组/字典或指针,请将其设置为nil/清空
  • 关键:将上述所有功能/方法放在一个函数/方法中,并确保在更改视图控制器之前正确调用它
*注意:如果你有一个用于整个应用程序的视图控制器(恭喜你压缩了所有东西-youz Overlard squeezer),那么不要将所有东西都置零,小心使用。但在演示过程中,前一个场景仍然需要设置为零

因此,如果您在视图控制器之间跳跃,则类似于这样:

/// Remove all pointers to any data, nodes & views.
fileprivate func cleanUp() {
    guard self.skView != nil else { return }
    // Session was passing data updates to this view controller; time to nil it
    self.gameSessionModel.delegate = nil
    self.skView.presentScene(nil)
    self.skViewMiniMap.presentScene(nil)
    self.skView = nil
    self.skViewMiniMap = nil
    for subview in self.view.subviews {
        subview.removeFromSuperview()
    }
}

/// Take the user back to the main menu module/view controller.
fileprivate func handleMenuButton() {
    // First, clean up everything
    self.cleanUp()
    // Then go to the other view controller
    let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "MainViewController")
    self.show(view, sender: .none)
}
调用
handleMenuButton()
函数或用于显示另一个视图控制器的任何函数,但请确保
[SKTexture preloadTextures:to_preload withCompletionHandler:^{
    [self fadeRemove:masterOverlay];
    [self initialize];
}];
/// Remove all pointers to any data, nodes & views.
fileprivate func cleanUp() {
    guard self.skView != nil else { return }
    // Session was passing data updates to this view controller; time to nil it
    self.gameSessionModel.delegate = nil
    self.skView.presentScene(nil)
    self.skViewMiniMap.presentScene(nil)
    self.skView = nil
    self.skViewMiniMap = nil
    for subview in self.view.subviews {
        subview.removeFromSuperview()
    }
}

/// Take the user back to the main menu module/view controller.
fileprivate func handleMenuButton() {
    // First, clean up everything
    self.cleanUp()
    // Then go to the other view controller
    let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "MainViewController")
    self.show(view, sender: .none)
}
/// Remove all pointers to any data, nodes & views.
fileprivate func cleanUp() {
    self.skView.presentScene(nil)
    // Previous scene was set to nil, its deinit called. Now onto the new scene:
    let gameScene = self.setupGameScene(id: "perhapsYouUseStringIDsToDisntiguishBetweenScenes?")
    self.skView.presentScene(gameScene)
}