SKShapeNode producing crash sometimes on dealloc EXC_BAD_ACCESS
在我的主要场景中,我使用以下方法创建4面墙:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | -(void)createFirstWalls{ CGFloat maxY = CGRectGetMaxY(self.frame); Wall* wall1=[Wall wallWithRect:self.frame color:[self randomColor] position:maxY andSpeed:speed]; Wall* wall2=[Wall wallWithRect:self.frame color:[self randomColor] position:maxY+distance andSpeed:speed]; Wall* wall3=[Wall wallWithRect:self.frame color:[self randomColor] position:maxY+distance*2 andSpeed:speed]; Wall* wall4=[Wall wallWithRect:self.frame color:[self randomColor] position:maxY+distance*3 andSpeed:speed]; wall1.name=@"1"; wall2.name=@"2"; wall3.name=@"3"; wall4.name=@"4"; [self addChild:wall1]; [self addChild:wall2]; [self addChild:wall3]; [self addChild:wall4]; } |
输掉比赛后,我会用经典方法呈现另一个场景
1 2 3 | SKScene* gameOver =[GameOver sceneWithSize:self.view.bounds.size]; gameOver.scaleMode = SKSceneScaleModeAspectFill; [self.view presentScene:gameOver]; |
问题在于,当我展示新场景时,ARC会释放我创建的所有墙,有时(或多或少有40%的机会)它会使执行崩溃。
这是我自定义的Wall类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | #import"Wall.h" static const uint32_t triangleCategory = 0x1 << 0; static const uint32_t wallCategory = 0x1 << 1; @implementation Wall +(id)wallWithRect:(CGRect)rect color:(UIColor*)color position:(CGFloat)point andSpeed:(CGFloat)speed{ return [[Wall alloc] initWithRect:rect color:color position:point andSpeed:speed]; } -(id)initWithRect:(CGRect)rect color:(UIColor*)color position:(CGFloat)point andSpeed:(CGFloat)speed{ if (self=[super init]) { CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, nil, CGRectGetMinX(rect), 100); CGPathAddLineToPoint(path, nil, CGRectGetMinX(rect), 115); CGPathAddLineToPoint(path, nil, CGRectGetMaxX(rect), 115); CGPathAddLineToPoint(path, nil, CGRectGetMaxX(rect), 100); CGPathAddLineToPoint(path, nil, CGRectGetMinX(rect), 100); self.position=CGPointMake(0, point); self.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:path]; self.physicsBody.linearDamping=0; self.physicsBody.affectedByGravity=NO; self.physicsBody.velocity=CGVectorMake(0,speed); self.physicsBody.collisionBitMask=0x0; self.physicsBody.contactTestBitMask=triangleCategory; self.physicsBody.categoryBitMask= wallCategory; self.path=path; CGPathRelease(path); path = nil; self.fillColor=color; self.lineWidth=2; self.strokeColor=[UIColor blackColor]; } return self; } -(void)dealloc{ NSLog(@"Wall: %@",self.name); } @end |
我创建了一个dealloc方法来查看会发生什么。
如果一切正常,则输出如下:
1 2 3 4 | 2014-08-19 15:56:42.252 running[36425:60b] Wall: 4 2014-08-19 15:56:42.256 running[36425:60b] Wall: 3 2014-08-19 15:56:42.257 running[36425:60b] Wall: 2 2014-08-19 15:56:42.260 running[36425:60b] Wall: 1 |
但是当崩溃时,输出是这样的:
1 2 | 2014-08-19 15:57:37.767 running[36425:60b] Wall: 4 (lldb) |
堆栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | SpriteKit`SKCSprite::removeSubsprite(SKCSprite*): 0x331751a4: push {r4, r5, r7, lr} 0x331751a6: add r7, sp, #0x8 0x331751a8: sub sp, #0x4 0x331751aa: mov r4, r0 0x331751ac: add.w r0, r4, #0x1bc 0x331751b0: mov r5, sp 0x331751b2: str r1, [sp] 0x331751b4: mov r1, r5 0x331751b6: bl 0x33179b8c ; unsigned long std::__1::__tree<SKCSprite*, std::__1::less<SKCSprite*>, std::__1::allocator<SKCSprite*> >::__erase_unique<SKCSprite*>(SKCSprite* const&) 0x331751ba: add.w r0, r4, #0x190 0x331751be: mov r1, r5 0x331751c0: bl 0x33179760 ; std::__1::list<SKCSprite*, std::__1::allocator<SKCSprite*> >::remove(SKCSprite* const&) 0x331751c4: ldr r5, [sp] 0x331751c6: ldrb r0, [r5, #0xa] 0x331751c8: ldrh r1, [r5, #0x8] 0x331751ca: orr.w r0, r1, r0, lsl #16 0x331751ce: tst.w r0, #0x2 0x331751d2: bne 0x331751e4 ; SKCSprite::removeSubsprite(SKCSprite*) + 64 0x331751d4: ldr.w r1, [r5, #412] 0x331751d8: ldr r1, [r1, #0x8] 0x331751da: cmp r1, #0x0 0x331751dc: it eq 0x331751de: tsteq.w r0, #0x100 0x331751e2: beq 0x331751ec ; SKCSprite::removeSubsprite(SKCSprite*) + 72 0x331751e4: mov r0, r4 0x331751e6: mov r1, r5 0x331751e8: bl 0x33179798 ; SKCSprite::removeFromOffscreenList(SKCSprite*) 0x331751ec: movs r0, #0x0 0x331751ee: str.w r0, [r5, #332] 0x331751f2: ldr r0, [r5] 0x331751f4: ldr r1, [r0, #0x28] 0x331751f6: mov r0, r5 0x331751f8: blx r1 0x331751fa: ldrh r0, [r4, #0xc] 0x331751fc: orr r1, r0, #0x40 0x33175200: strh r1, [r4, #0xc] 0x33175202: ldr.w r0, [r4, #332] 0x33175206: cbz r0, 0x3317522c ; SKCSprite::removeSubsprite(SKCSprite*) + 136 0x33175208: add.w r1, r4, #0x14c 0x3317520c: ldrh r2, [r0, #0xc] 0x3317520e: orr r2, r2, #0x40 0x33175212: strh r2, [r0, #0xc] Thread 1: EXC_BAD_ACCESS(code=2, address=0x302e373d) 0x33175214: ldr r1, [r1] 0x33175216: ldrh r0, [r1, #0xc] 0x33175218: orr r0, r0, #0x40 0x3317521c: strh r0, [r1, #0xc] 0x3317521e: ldr.w r0, [r1, #332] 0x33175222: add.w r1, r1, #0x14c 0x33175226: cmp r0, #0x0 0x33175228: bne 0x3317520c ; SKCSprite::removeSubsprite(SKCSprite*) + 104 0x3317522a: ldrh r1, [r4, #0xc] 0x3317522c: orr r0, r1, #0x2 0x33175230: strh r0, [r4, #0xc] 0x33175232: b 0x33175236 ; SKCSprite::removeSubsprite(SKCSprite*) + 146 0x33175234: ldrh r0, [r4, #0xc] 0x33175236: tst.w r0, #0x80 0x3317523a: bne 0x3317524a ; SKCSprite::removeSubsprite(SKCSprite*) + 166 0x3317523c: orr r0, r0, #0x80 0x33175240: strh r0, [r4, #0xc] 0x33175242: ldr.w r4, [r4, #332] 0x33175246: cmp r4, #0x0 0x33175248: bne 0x33175234 ; SKCSprite::removeSubsprite(SKCSprite*) + 144 0x3317524a: add sp, #0x4 0x3317524c: pop {r4, r5, r7, pc} 0x3317524e: nop |
我尝试了一些类似的事情,例如在解除分配之前将物理体设置为零,但是没有任何效果...任何想法?
这似乎是iOS 7.1中的SKShapeNode的错误...
但是最后我找到了答案!!!希望这可以帮助更多的人。
我实现了一种方法来删除当前节点中的所有子元素
1 2 3 4 5 6 | - (void)cleanUpChildrenAndRemove:(SKNode*)node { for (SKNode *child in node.children) { [self cleanUpChildrenAndRemove:child]; } [node removeFromParent]; } |
然后在呈现新场景之前调用该函数
1 2 3 4 | [self cleanUpChildrenAndRemove:self]; //god bless this method SKScene* gameOver =[GameOver sceneWithSize:self.view.bounds.size]; gameOver.scaleMode = SKSceneScaleModeAspectFill; [self.view presentScene:gameOver]; |
不再崩溃,也不会BAD_EXC ...是一个真正的奇迹。
一个可能的原因是您没有释放CGPathRef对象。请参阅此问题/答案。
尝试在最后使用路径添加以下两行:
1 2 3 4 | self.path=path; CGPathRelease(path); path = nil; |
过去也存在一个错误,其中删除SKShapeNodes导致崩溃。确保运行最新的Xcode 5版本/ iOS 7.1 SDK。