SKShapeNode生成崩溃有时在dealloc EXC_BAD_ACCESS [英] SKShapeNode producing crash sometimes on dealloc EXC_BAD_ACCESS
问题描述
在我的主场景中,我使用此方法创建4个墙:
- (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];
}
我失去了游戏后, p>
SKScene * gameOver = [GameOver sceneWithSize:self.view.bounds.size];
gameOver.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:gameOver];
问题是当我提出新的场景时,ARC会重新分配我创建的所有墙,
这是我的自定义Wall类:
#importWall.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: )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 = [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方法看看会发生什么。
如果一切正常,输出结果如下:
2014-08-19 15:56:42.252 running [ 36425:60b]墙:4
2014-08-19 15:56:42.256 running [36425:60b]墙: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
但是当崩溃的输出是这样:
2014-08-19 15:57:37.767 running [36425 :60b] Wall:4
(lldb)
堆栈:
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, #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, #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
我试过一些事情之前解开分配设置物理主体为nil,但没有什么工作...任何想法?
解决方案这似乎是iOS7中的SKShapeNode的错误...
但是终于我找到了答案!希望这可以帮助更多的人。
我实现了一个方法来删除当前节点中的所有孩子
- (void)cleanUpChildrenAndRemove:(SKNode *)node {
for(SKNode * child in node.children){
[self cleanUpChildrenAndRemove:child];
}
[node removeFromParent];
}
然后在提出新场景之前调用该函数
[self cleanUpChildrenAndRemove:self]; //上帝保佑这个方法
SKScene * gameOver = [GameOver sceneWithSize:self.view.bounds.size];
gameOver.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:gameOver];
没有更多崩溃或BAD_EXC ...真正的奇迹。
In my main scene I create 4 walls with this method:
-(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];
}
After I lose the game, I present another scene with the classic method
SKScene* gameOver =[GameOver sceneWithSize:self.view.bounds.size];
gameOver.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:gameOver];
The problem is that when I present the new scene, the ARC deallocates all the walls I have created, and sometimes (40% chances more or less) it crashes the execution.
This is my custom Wall class:
#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
I create a dealloc method to see what happens.
If all it's good, the output is this:
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
But when crashes the output is this:
2014-08-19 15:57:37.767 running[36425:60b] Wall: 4
(lldb)
The stack:
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
I tried some things like before deallocation setting the physicsbody to nil but nothing works... any ideas?
解决方案 It seems to be a bug with the SKShapeNode in iOS 7.1 ...
But finally I found the answer!!! Hope this can help more people.
I implemented a method to remove all the childs in the current node
- (void)cleanUpChildrenAndRemove:(SKNode*)node {
for (SKNode *child in node.children) {
[self cleanUpChildrenAndRemove:child];
}
[node removeFromParent];
}
And then call that function before I present a new scene
[self cleanUpChildrenAndRemove:self]; //god bless this method
SKScene* gameOver =[GameOver sceneWithSize:self.view.bounds.size];
gameOver.scaleMode = SKSceneScaleModeAspectFill;
[self.view presentScene:gameOver];
No more crashes nor BAD_EXC... A true miracle.
这篇关于SKShapeNode生成崩溃有时在dealloc EXC_BAD_ACCESS的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!