问题
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:
Having a SKShapeNode (either a subclass OR a child of a SKNode)
Having a SKPhysicsNode attached to a node (attached to a parent SKNode OR the SKShapeNode).
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