SpriteKit中的EXC_BAD_ACCESS(代码= 1,地址= 0x0)

时间:2014-10-24 21:52:48

标签: objective-c crash sprite-kit exc-bad-access

我目前正在为iPhone编写游戏编码,我有时会因标题中的错误而随机崩溃。

我研究了很多,可能与泄漏(?)内存问题有关。我问过的人告诉我,这可能与添加一个零对象有关。我设置了异常断点和NSZombies,但是这些都没有识别崩溃,也没有给我发生崩溃的确切代码行。

经过一些碰撞测试后,我注意到,当touchesBegan方法或didBeganContact方法处于活动状态时,大部分时间都会发生。

这里是touchesBegan方法和didBeginContact方法的代码:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if (touchEnabled == YES){
    firstTouch++;
    if (firstTouch == 1){
        SKAction* removeFade = [SKAction removeFromParent];
        SKAction* startFade = [SKAction fadeAlphaTo:0 duration:0.5];
        SKAction* fadeSeq = [SKAction sequence:@[startFade, removeFade]];
        [startScreen runAction:fadeSeq completion:^{
            startScreenRemoved = YES;
            [self gameCountdown];
            touchToShoot = YES;
        }];   
    }
    if (firstTouch == 2){
        weaponActivated = YES;
    }

    if (gameOver == YES){
        [self removeAllActions];
        [self removeAllChildren];
        [bgPlayer stop];
        touchToShoot = NO;
        SKScene* gameScene = [[GameScene alloc] initWithSize:self.size];

        SKTransition *doors = [SKTransition doorsOpenVerticalWithDuration:1];

        [self.view presentScene:gameScene transition:doors];
        gameOver = NO;
               }

    }

    if (touchToShoot == YES) {

        [self weaponParticle];

        touchToShoot = NO;

        [self performSelector:@selector(enableTouchToShoot) withObject:nil afterDelay:0.3]; //-enableTouchToShoot{} = touchToShoot = YES;

    }

    //Pause Button
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    SKNode *node = [self nodeAtPoint:location];

    if ([node.name isEqualToString:@"pauseButton"]) {
        [self pauseMenu];

    }
    else if ([node.name isEqualToString:@"continue"]) {

        self.paused = NO;

        pauseBG.hidden = YES;
        pauseText.hidden = YES;
        backm.hidden = YES;
        cont.hidden = YES;

        //Damit unsichtbare Buttons nicht während dem Spiel gedrückt werden

        backm.zPosition = -100;

        cont.zPosition = -100;

    }
    else if ([node.name isEqualToString:@"backtomenu"]) {
        self.paused = NO;
        [self displayAlert];
    }

}

-(void)didBeginContact:(SKPhysicsContact *)contact{   

    if (contact.bodyA.categoryBitMask == shipCategory) {

        //Explosion Animation
        SKAction* wait =[SKAction waitForDuration:0.5];
        SKAction* fadeOut = [SKAction scaleTo:0.0 duration:1];
        remove = [SKAction removeFromParent];


        explodeSequenceGO =[SKAction sequence:@[fadeOut,wait,remove]];


        ExplosionPath = [[NSBundle mainBundle] pathForResource:@"Explosion" ofType:@"sks"];
        Explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:ExplosionPath];
        Explosion.position = CGPointMake(contact.bodyA.node.position.x, contact.bodyA.node.position.y);
        [self addChild:Explosion];
        [Explosion runAction:explodeSequenceGO];

        [contact.bodyA.node removeFromParent];
        [contact.bodyB.node removeFromParent];
        [shipSmoke removeFromParent];
        [player1 removeFromParent];

        touchEnabled = NO;
        [self gameOver];

    }


    if (contact.bodyA.categoryBitMask == enemyCategory || contact.bodyB.categoryBitMask == enemyCategory) {

        //Explosion Animation
        SKAction* wait =[SKAction waitForDuration:0.5];
        SKAction* fadeOut = [SKAction scaleTo:0.0 duration:1];
        remove = [SKAction removeFromParent];
        explodeSequenceGO =[SKAction sequence:@[fadeOut,wait,remove]];

        ExplosionPath = [[NSBundle mainBundle] pathForResource:@"Explosion" ofType:@"sks"];
        Explosion = [NSKeyedUnarchiver unarchiveObjectWithFile:ExplosionPath];
        Explosion.position = CGPointMake(contact.bodyA.node.position.x, contact.bodyA.node.position.y);

        [Explosion runAction:explodeSequenceGO];
        [self addChild:Explosion];
        [contact.bodyA.node removeFromParent];
        [contact.bodyB.node removeFromParent];


        hitCount++;
        [self scoreChange:100];
    }

    if (hitCount>39) {
        [self eLevel2];
    }

}

有人看到错吗?我非常感谢任何提示,因为我几周都在寻找这个bug ....

编辑:崩溃只指向"主要"功能,根本没有帮助

The crash just points to the "main" function, which doesn't help at all

并且在每个线程"动作"它只是指向Assembly(?)代码: link

就像我说的那样,我试图通过各种调试工具(NSZombies,MemoryTool,Exceptional Breakouts等)来分析崩溃,但是没有一个给我有用的信息。当应用程序崩溃时,调试工具就会停止录制,但是他们不会向我显示任何错误或崩溃结果。

2 个答案:

答案 0 :(得分:2)

我知道这已经有几个月了,但是当我从一个场景转换到另一个场景时,我也遇到了EXC_BAD_ACCESS错误。阅读了多篇文章,并在我的游戏中几乎每行代码都进行了评论,为我修复的是从方法返回之前从现有场景中删除所有对象,并且错误消失了。

- (void)returnToMenuScene {

    SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
    MenuScene *menuScene = [MenuScene sceneWithSize:self.scene.size];
    [self.scene.view presentScene:menuScene transition:reveal];

    [self.gameScene removeAllChildren];

    return;
}

- (GameScene *)gameScene {

    return (GameScene *)self.scene;
}

我希望将来可以帮助其他人

答案 1 :(得分:1)

我早期发现的一件事是,如果原始场景被SpriteKit过早杀死,场景之间的转换会导致崩溃。 - 我知道疯狂的谈话。

为了帮助我,我创建了一个基类场景,其中包括一个清理操作。

-(void)cleanUp
{
    [self cleanUpChildrenAndRemove:self];
}


- (void)cleanUpChildrenAndRemove:(SKNode*)node {
    for (SKNode* child in node.children) {
        [self cleanUpChildrenAndRemove:child];
    }
    [node removeFromParent];
}

然后当我转换场景时,我让旧场景生存一段时间然后再摧毁它。 请注意在旧场景上使用操作以便稍后清理自己。 叫我偏执,妄想,但它修复了我的崩溃。当我在应用程序上收到Terminate事件时,我还需要调用清理。

if( oldscene!=nil )
{
    SKTransition* doors = [SKTransition doorsOpenVerticalWithDuration:1.5];
    doors.pausesIncomingScene = NO;
    [[self view] presentScene:newscene transition:doors];

    SKNode* dummynode = [SKNode node];

    // wait for the transition to complete before we give up the referene to oldscene
    [dummynode runAction:[SKAction waitForDuration:2.0] completion:^{
        if ([oldscene isKindOfClass:[MyBaseScene class]])
        {
            // failing to clean up nodes can result in crashes... nice.
            [((MyBaseScene*)oldscene) cleanUp];
        }}];
    [oldscene addChild:dummynode];
}
else
{
    [[self view] presentScene:newscene];
}