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

时间:2023-01-23 00:07:39

I am currently coding a game for the iPhone and I sometimes get random crashes with the error in the title.

我现在正在为iPhone编写一个游戏,我有时会在标题中出现错误。

I've researched quite a bit and it probably has to do with leaking(?) memory issues. The people I asked told me, that it may has to do with adding a nil object. I set up exception breakpoints and NSZombies but neither of those recognize the crash, nor give me the exact code line where the crash occurs.

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

After some crash-testing I noticed that most of the time it happens when either the touchesBegan method or the didBeganContact method is active.

在进行了一些紧急测试之后,我注意到,在大多数情况下,无论是touchesBegan方法还是didBeganContact方法都是活动的。

Here's the code of the touchesBegan method and the didBeginContact method:

这是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];
    }

}

Does anyone see a fault? I greatly appreciate any tip, since I am searching for this bug for weeks....

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

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

编辑:崩溃只指向“main”函数,这没有任何帮助

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

And in each of the Thread "actions" it just points to Assembly(?) code: EXC_BAD_ACCESS(代码=1,地址=0x0)在SpriteKit中

在每个线程的“动作”中,它只指向汇编(?)代码:

And like I said, I tried to analyze the crashes by various debug tools (NSZombies, MemoryTool, Exceptional Breakouts, etc.) but none of them give me useful infos. When the app crashes, the debugging tools just stop recording, but they don't show me any faults or crash results.

就像我说的,我试着用各种调试工具(nszombie, MemoryTool, exception out等等)分析崩溃,但是没有一个工具给我有用的信息。当应用程序崩溃时,调试工具会停止记录,但不会显示任何错误或崩溃结果。

2 个解决方案

#1


2  

I know that this is a few months old, but I too was experiencing the EXC_BAD_ACCESS error when transitioning from one scene to another. After reading multiple posts, and commenting out almost every line of code in my game, what fixed it for me was the removing all of the objects from the existing scene before returning from the method and bang error was gone.

我知道这已经有几个月的历史了,但是在从一个场景切换到另一个场景时,我也遇到了EXC_BAD_ACCESS错误。在阅读了多篇文章,并注释掉了我游戏中的几乎每一行代码之后,我解决的问题是在方法返回之前将所有的对象从现有场景中删除,而bang错误则消失了。

- (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;
}

I hope this helps someone else in the future

我希望这能在将来帮助别人

#2


1  

One thing I found early on is that transitioning between scenes caused crashes if the original scene was killed too early by SpriteKit. - Crazy talk I know.

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

To help this I created a base class scene which included a cleanup op.

为此,我创建了一个包含清理操作的基类场景。

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


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

Then when i transition scenes, I let the old scene live for a while before destroying it. Notice the use of an action on the old scene to clean itself up later on. Call me paranoid, delusional, but it fixed my crash. I also needed to call cleanup when I received Terminate events on the App.

然后当我转换场景的时候,我让旧场景在破坏它之前存在一段时间。注意在旧场景中使用动作来清理自己。叫我妄想狂,妄想狂,但它修复了我的崩溃。当我收到App上的终止事件时,我还需要调用cleanup。

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];
}

#1


2  

I know that this is a few months old, but I too was experiencing the EXC_BAD_ACCESS error when transitioning from one scene to another. After reading multiple posts, and commenting out almost every line of code in my game, what fixed it for me was the removing all of the objects from the existing scene before returning from the method and bang error was gone.

我知道这已经有几个月的历史了,但是在从一个场景切换到另一个场景时,我也遇到了EXC_BAD_ACCESS错误。在阅读了多篇文章,并注释掉了我游戏中的几乎每一行代码之后,我解决的问题是在方法返回之前将所有的对象从现有场景中删除,而bang错误则消失了。

- (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;
}

I hope this helps someone else in the future

我希望这能在将来帮助别人

#2


1  

One thing I found early on is that transitioning between scenes caused crashes if the original scene was killed too early by SpriteKit. - Crazy talk I know.

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

To help this I created a base class scene which included a cleanup op.

为此,我创建了一个包含清理操作的基类场景。

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


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

Then when i transition scenes, I let the old scene live for a while before destroying it. Notice the use of an action on the old scene to clean itself up later on. Call me paranoid, delusional, but it fixed my crash. I also needed to call cleanup when I received Terminate events on the App.

然后当我转换场景的时候,我让旧场景在破坏它之前存在一段时间。注意在旧场景中使用动作来清理自己。叫我妄想狂,妄想狂,但它修复了我的崩溃。当我收到App上的终止事件时,我还需要调用cleanup。

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];
}