正确地重新启动/重新初始化半单例

时间:2013-06-30 23:36:54

标签: ios cocos2d-iphone

我正在使用半单身方法进行我的cocos2d游戏的主要游戏层/场景,如后面的代码所示。

目标是通过调用: [[GameLayer sharedGameLayer] restart] 方法,使用暂停或游戏结构层中的按钮正确重启/重新创建此单例场景。< / p>

问题是指我使用CCTransition效果,并使用 sharedGameLayer = nil; 行覆盖GameLayer的 dealloc 方法(至确保重置静态变量),sharedGameLayer变量在第一次重启后保持为nil(也就是在第一次dealloc之后),因此调用 restart 方法什么都不做。

怀疑有用的根本不会覆盖 dealloc 方法,但在使用 replaceScene:重新启动场景之前,我设置了sharedGameLayer为nil。

问题:这是重启/重新创建这个半单身类的正确方法吗?

提前致谢。

代码:

GameLayer.m:

static GameLayer *sharedGameLayer;

@implementation GameLayer

- (id)init
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    // always call "super" init
    // Apple recommends to re-assign "self" with the "super's" return value
    if (self = [super initWithColor:ccc4(255, 255, 255, 255) width:[CCDirector sharedDirector].winSize.width
                             height:[CCDirector sharedDirector].winSize.height])
    {

        // Set the sharedGameLayer instance to self.
        sharedGameLayer = self;

        // Set the initial game state.
        self.gameState = kGameStateRunning;

        // Register with the notification center in order to pause the game when game resigns the active state.
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(pauseGame) name:UIApplicationWillResignActiveNotification object:nil];

        // Enable touches and multi-touch.
        CCDirector *director = [CCDirector sharedDirector];
        [director.touchDispatcher addTargetedDelegate:self priority:0 swallowsTouches:YES];
        director.view.multipleTouchEnabled = YES;


        // Set the initial score.
        self.score = 5;

        // Create the spiders batch node.
        [self createSpidersBatchNode];

        // Load the game assets.
        [self loadAssets];


        // Play Background music.
        if (![SimpleAudioEngine sharedEngine].isBackgroundMusicPlaying)
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"backgroundmusic.mp3" loop:YES];

        // Preload sound effects.
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"inbucket.mp3"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"outbucket.mp3"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"gameover.mp3"];

        // Schdule updates.
        [self scheduleUpdate];
        [self schedule:@selector(releaseSpiders) interval:0.7];
    }

    return self;
}



- (void)createSpidersBatchNode
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    // BatchNode. (For Animation Optimization)
    self.spidersBatchNode = [CCSpriteBatchNode batchNodeWithFile:@"spiderAtlas.png"];

    // Spider sprite + BatchNode + animation action.
    for (int i = 0; i < 50; i++) {
        Spider *spider = [[Spider alloc] init];
        spider.spiderSprite.visible = NO;
    }

    [self addChild:self.spidersBatchNode];
}



- (void)restartGame
{
    // Play button pressed sound effect.
    [[SimpleAudioEngine sharedEngine] playEffect:@"button.mp3"];

    // Nil'ing the static variable.
    sharedGameLayer = nil;

    // Restart game.
    [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[GameLayer scene]]];
}



+ (CCScene *)scene
{
    // 'scene' is an autorelease object.
    CCScene *scene = [CCScene node];

    // Game Layer.
     // 'gameLayer' is an autorelease object.
    GameLayer *gameLayer = [GameLayer node];

     // add gameLayer as a child to scene
    [scene addChild: gameLayer];

    // HUD Layer.
    HUDLayer *hudLayer = [HUDLayer node];
    [scene addChild:hudLayer];
    gameLayer.hud = hudLayer;

    // return the scene
    return scene;
}



+ (GameLayer *)sharedGameLayer
{
    return sharedGameLayer;
}



- (void)cleanup
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[CCDirector sharedDirector].touchDispatcher removeDelegate:self];
    [self stopAllActions];
    [self unscheduleAllSelectors];
    [self unscheduleUpdate];

    [self removeAllChildrenWithCleanup:YES];
    self.hud = nil;

    [super cleanup];
}



//- (void)dealloc
//{
//    sharedGameLayer = nil;
//}


@end

2 个答案:

答案 0 :(得分:0)

我敢打赌你的新游戏层是在第一个游戏层解除分配之前创建的,因此它将静态var设置为nil。在dealloc中检查sharedGameLayer是否等于self。

答案 1 :(得分:0)

不要使用dealloc将静态变量设置为nil。 对象停止使用后,Dealloc发生。切勿使用它来控制应用的行为。

众所周知,将sharedGameLayer设置为nil和调用dealloc方法之间可能已经过了30分钟。或者dealloc 永远不会被调用

您的代码看起来不错,只需删除注释掉的“dealloc”代码。

此外,此代码:

[[NSNotificationCenter defaultCenter] removeObserver:self];

除了您的自定义-dealloc方法之外,还应该使用-cleanup方法。移除一个观察者两次是完全没问题的,如果它已被移除,则不会发生任何事情。

另一个注意事项,+sharedGameLayer应该返回instancetype类型的变量,它应该负责设置sharedGameLayer变量。如果您在sharedGameLayer-init,则会遇到错误。

例如:

+ (instancetype)sharedGameLayer
{
    if (sharedGameLayer)
        return sharedGameLayer;

    sharedGameLayer = [[[self class] alloc] init];

    return sharedGameLayer;
}

- (id)init
{
    if (!(self = [super init]))
        return nil;

    .
    .
    .

    return self;
}