Sprite Kit iOS 7.1 crash on removeFromParent

社会主义新天地 提交于 2019-11-26 08:19:45

问题


I have updated iPad Air to 7.1 and Xcode to 5.1. Xcode wanted to update my project to recommended settings, I agreed.

After that my game began crashing in a couple of places when I remove node from parent.

That was a surprise for me — there were no crossings before the update. I restored my project and found out what Xcode does to it — only changes Architectures string:

Before:

After:

In the old version there are no crashes. There are no crashes if I remove arm64 support in new version. In the simulator there are no crashes in both new and old versions.

Where should I pay attention in my code?

Code stack:

SpriteKit`SKCSprite::removeSubsprite(SKCSprite*):
0x1859442cc:  stp    fp, lr, [sp, #-16]!
0x1859442d0:  add    fp, sp, 0
0x1859442d4:  stp    x20, x19, [sp, #-16]!
0x1859442d8:  sub    sp, sp, #16
0x1859442dc:  mov    x19, x0
0x1859442e0:  str    x1, [sp, #8]
0x1859442e4:  add    x20, sp, 8
0x1859442e8:  add    x0, x19, 544
0x1859442ec:  mov    x1, x20
0x1859442f0:  bl     0x18594872c               ; unsigned long std::__1::__tree<SKCSprite*, std::__1::less<SKCSprite*>, std::__1::allocator<SKCSprite*> >::__erase_unique<SKCSprite*>(SKCSprite* const&)
0x1859442f4:  add    x0, x19, 464
0x1859442f8:  mov    x1, x20
0x1859442fc:  bl     0x185948218               ; std::__1::list<SKCSprite*, std::__1::allocator<SKCSprite*> >::remove(SKCSprite* const&)
0x185944300:  ldr    x20, [sp, 1]
0x185944304:  ldrb   w8, [x20, #18]
0x185944308:  ldrh   w9, [x20, #16]
0x18594430c:  orr    w8, w9, w8, lsl #16
0x185944310:  tbnz   w8, #1, 0x185944324       ; SKCSprite::removeSubsprite(SKCSprite*) + 88
0x185944314:  ldr    x9, [x20, 61]
0x185944318:  ldr    x9, [x9, 2]
0x18594431c:  cbnz   x9, 0x185944324           ; SKCSprite::removeSubsprite(SKCSprite*) + 88
0x185944320:  tbz    w8, #8, 0x185944330       ; SKCSprite::removeSubsprite(SKCSprite*) + 100
0x185944324:  mov    x0, x19
0x185944328:  mov    x1, x20
0x18594432c:  bl     0x18594828c               ; SKCSprite::removeFromOffscreenList(SKCSprite*)
0x185944330:  str    xzr, [x20, #392]
0x185944334:  ldr    x8, [x20, 0]
0x185944338:  ldr    x8, [x8, 10]
0x18594433c:  mov    x0, x20
0x185944340:  blr    x8
0x185944344:  ldrh   w8, [x19, #20]
0x185944348:  orr    w9, w8, #0x40
0x18594434c:  strh   w9, [x19, #20]
0x185944350:  ldr    x8, [x19, 49]
0x185944354:  cbz    x8, 0x185944388           ; SKCSprite::removeSubsprite(SKCSprite*) + 188
0x185944358:  add    x9, x19, 392
0x18594435c:  ldrh   w10, [x8, #20]
0x185944360:  orr    w10, w10, #0x40
0x185944364:  strh   w10, [x8, #20]
0x185944368:  ldr    x8, [x9, 0]
0x18594436c:  add    x9, x8, 392
0x185944370:  ldrh   w10, [x8, #20]
0x185944374:  orr    w10, w10, #0x40
0x185944378:  strh   w10, [x8, #20]
0x18594437c:  ldr    x8, [x8, 49]
0x185944380:  cbnz   x8, 0x18594435c           ; SKCSprite::removeSubsprite(SKCSprite*) + 144
0x185944384:  ldrh   w9, [x19, #20]  EXC_BAD_ACCESS here.
0x185944388:  orr    w8, w9, #0x2
0x18594438c:  strh   w8, [x19, #20]
0x185944390:  b      0x185944398               ; SKCSprite::removeSubsprite(SKCSprite*) + 204
0x185944394:  ldrh   w8, [x19, #20]
0x185944398:  tbnz   w8, #7, 0x1859443ac       ; SKCSprite::removeSubsprite(SKCSprite*) + 224
0x18594439c:  orr    w8, w8, #0x80
0x1859443a0:  strh   w8, [x19, #20]
0x1859443a4:  ldr    x19, [x19, 49]
0x1859443a8:  cbnz   x19, 0x185944394          ; SKCSprite::removeSubsprite(SKCSprite*) + 200
0x1859443ac:  sub    sp, fp, #16
0x1859443b0:  ldp    x20, x19, [sp], #16
0x1859443b4:  ldp    fp, lr, [sp], #16
0x1859443b8:  ret    lr

UPDATE: New information:

My error:

Stack:

I found out something wrong. My node I want to remove consists of two SKSpriteNodes (my sprite image and its shadow) and one SKShapeNode (a thin black rope). I tried to replace my SKShapeNode rope with a SKSpriteNode rope and I got success — problem gone.

Code to remove my node from parent:

SKAction *moveCloud = [SKAction moveToX:destinationX duration:moveDuration];
[cloud runAction:moveCloud completion:^{
    [cloud removeFromParent];
}];

Code to add a SKShapeNode rope to my node:

- (void)addRopeToCloud:(SKNode *)cloud
{
    CGFloat maxY = self.scene.size.height;
    CGFloat length = maxY - [self.scene convertPoint:cloud.position fromNode:cloud.parent].y;

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, 0, 0);
    CGPathAddLineToPoint(path, NULL, 0, length);

    SKShapeNode *rope = [[SKShapeNode alloc] init];
    rope.path = path;
    rope.strokeColor = [UIColor blackColor];
    rope.lineWidth = 0.1;
    rope.antialiased = YES;
    rope.zPosition = -0.01;

    CGFloat threadScale = 1 / cloud.xScale;

    rope.xScale = threadScale;
    rope.yScale = threadScale;

    [cloud addChild:rope];
    CGPathRelease(path);
}

Code to add a SKSpriteNode rope to my node, that resolves the problem:

- (void)addRopeToCloud:(SKNode *)cloud
{
    CGFloat maxY = self.scene.size.height;
    CGFloat length = maxY - [self.scene convertPoint:cloud.position fromNode:cloud.parent].y;

    CGSize ropeSize = CGSizeMake(1.5, length);
    SKSpriteNode *rope = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:ropeSize];
    rope.anchorPoint = CGPointMake(0.5, 0);

    CGFloat ropeScale = 1 / cloud.xScale;
    rope.xScale = ropeScale;
    rope.yScale = ropeScale;

    rope.zPosition = -0.01;

    [cloud addChild:rope];
}

It looks like something wrong in my SKShapeNode adding code, but I can\'t understand what exactly is.


回答1:


I also crash with SKShapeNode when its parent remove from superview in iOS 7.1

My work around is set SKShapeNode property to nil before it remove from parent




回答2:


It seems to only happen on iOS 7.1. Not sure if it is an Apple bug, but this seems to fix it:

- (void)removeFromParent
{
    [self.aShapeNode removeFromParent];
    self.aShapeNode = nil;

    [super removeFromParent];
}



回答3:


You can call this method before you dealloc (or present new scene) the SKShapeNodes

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

I had the same problem but that solved it. My original question:

SKShapeNode producing crash sometimes on dealloc EXC_BAD_ACCESS




回答4:


Not sure if my situation exactly mimics yours, but I was getting the same error (with the same stack trace) and realized that I had set up two classes that were each keeping the SKShapeNode object as properties. I'm pretty sure that when I called removeFromParent to remove object node in ClassA the object was deallocated. Then, in ClassB, I called self.node = aNewNode (keep in mind that the object that self.node pointed to had been deallocated), the auto-synthesized setter tried to de-allocate node for a second time.

I thought ARC was supposed to keep track of all this, but the bug is very sporadic so I'm honestly not 100% sure what's going on. I have an SKSpriteNode with the same pattern and I have never seen it causing this error. My fix right now has been to make the ClassB property weak, so it's not a problem if self.node has already been deallocated. Hope that helps!




回答5:


I am also experiencing the crash. However, the solutions to override the removeFromParent method and setting the SKShapeNode to nil didn't work for me.

I did discover that my crash was the combination of:

  1. Having a SKShapeNode (either a subclass OR a child of a SKNode)

  2. Having a SKPhysicsNode attached to a node (attached to a parent SKNode OR the SKShapeNode).

  3. Calling the method removeFromParent

The solution I ended up using was overriding the removeFromParent method in my SKShapeNode subclass with the following:

- (void)removeFromParent
{
    if( self.physicsBody != nil )
    {
        self.physicsBody = nil;
    }

    [super removeFromParent];
}


来源:https://stackoverflow.com/questions/22399278/sprite-kit-ios-7-1-crash-on-removefromparent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!