iOS 8 SpriteKit在块/动作中添加或删除子节点时崩溃

12

iOS8 版本以后,我的游戏突然开始崩溃。经过一番调试,我发现游戏在以下两个地方崩溃:

 [sparkNode runAction:[SKAction sequence:@[
                                           //Some actions and finally...
                                           [SKAction removeFromParent]]]]; // Crashes here (If I remove this action no crash occurs)

其次是:

[rankTransitionSprite runAction:[SKAction sequence:@[[SKAction scaleTo:1.5 duration:1.0],
                                                     [SKAction runBlock:^{
    CGPoint rankPosition = _rankSprite.position;
    [_rankSprite removeFromParent];
    _rankSprite = [_spritesFactory spriteFromAtlasForImageName:[NSString stringWithFormat:@"rank%d", rank]];
    [self addChild:_rankSprite]; // Crashes here
}],
                                                     [SKAction scaleTo:0.0 duration:1.0],
                                                     [SKAction removeFromParent]]]];

在iOS 7.1上不会发生崩溃。只有在iOS8上才会崩溃。 对于第一个崩溃,我用以下内容替换了removeFromParent操作:

[SKAction runBlock:^{
                      dispatch_async(dispatch_get_main_queue(), ^{
                           [sparkNode removeFromParent]; 
                      });
}]

这似乎解决了问题。

对于第二次崩溃,我做了同样的事情(在主线程中添加精灵),崩溃消失了。

崩溃日志:

Thread 0 Crashed:: Dispatch queue: com.apple.spritekit.renderQueue
0   SpriteKit                       0x000000010abed9fe SKCRenderer::preprocessSpriteImp(std::__1::vector<SKCRenderer::SpriteRenderInfo, std::__1::allocator<SKCRenderer::SpriteRenderInfo> >&, SKRenderQuadPool&, SKCSprite const*, _GLKMatrix4 const&, float, unsigned int&, bool) + 372
1   SpriteKit                       0x000000010abee82b SKCRenderer::preprocessSpriteImp(std::__1::vector<SKCRenderer::SpriteRenderInfo, std::__1::allocator<SKCRenderer::SpriteRenderInfo> >&, SKRenderQuadPool&, SKCSprite const*, _GLKMatrix4 const&, float, unsigned int&, bool) + 4001
2   SpriteKit                       0x000000010abee82b SKCRenderer::preprocessSpriteImp(std::__1::vector<SKCRenderer::SpriteRenderInfo, std::__1::allocator<SKCRenderer::SpriteRenderInfo> >&, SKRenderQuadPool&, SKCSprite const*, _GLKMatrix4 const&, float, unsigned int&, bool) + 4001
3   SpriteKit                       0x000000010abe7c21 SKCRenderer::preprocessAndSubmitSpriteInternal(std::__1::vector<SKCRenderer::SpriteRenderInfo const*, std::__1::allocator<SKCRenderer::SpriteRenderInfo const*> >&, std::__1::vector<SKCRenderer::SpriteRenderInfo, std::__1::allocator<SKCRenderer::SpriteRenderInfo> >&, SKRenderQuadPool&, SKCSprite const*, _GLKMatrix4 const&) + 139
4   SpriteKit                       0x000000010abeb7d1 SKCRenderer::submitScene(SKScene*, bool) + 393
5   SpriteKit                       0x000000010abeff16 SKCRenderer::renderScene(SKScene*, bool) + 86
6   SpriteKit                       0x000000010ab87542 -[SKView _renderContent] + 1027
7   libdispatch.dylib               0x000000010c974b94 _dispatch_client_callout + 8
8   libdispatch.dylib               0x000000010c9611e7 _dispatch_barrier_sync_f_invoke + 76
9   SpriteKit                       0x000000010ab870f3 -[SKView renderContent] + 89
10  SpriteKit                       0x000000010ab8415c __29-[SKView setUpRenderCallback]_block_invoke + 54
11  SpriteKit                       0x000000010abb0a54 -[SKDisplayLink _callbackForNextFrame:] + 256
12  QuartzCore                      0x000000010ecf0967 CA::Display::DisplayLinkItem::dispatch() + 37
13  QuartzCore                      0x000000010ecf082f CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 315
14  CoreFoundation                  0x000000010b39e4d4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
15  CoreFoundation                  0x000000010b39e095 __CFRunLoopDoTimer + 1045
16  CoreFoundation                  0x000000010b3613cd __CFRunLoopRun + 1901
17  CoreFoundation                  0x000000010b3609f6 CFRunLoopRunSpecific + 470
18  GraphicsServices                0x000000010d41d9f0 GSEventRunModal + 161
19  UIKit                           0x00000001098cb990 UIApplicationMain + 1282

我的问题是为什么它只在iOS8上崩溃?(在许多iOS 7.1测试中从未发生过崩溃)


1
我对根本原因没有任何信息,但我想指出另一个好的解决方法是将removeFromParent示例放在runAction的完成块中。像这样:[node runAction:[SKAction fadeOutWithDuration:1.0] completion:^{ [node removeFromParent]; }]; - Karl Voskuil
我认为这种情况(至少在我的游戏中)发生在我在碰撞时删除精灵,然后Sprite Kit的内部shouldCullNonVisibleNodes试图移除该精灵,但它已从内存中删除。当我在碰撞时从父级中删除子级时,我遇到了这个问题,但后来发现碰撞仍在运行。- (void)weapon:(Weapon *)weapon didCollideWithMonster:(Monster *)monster { if (weapon.parent) { [weapon removeFromParent]; } }检查精灵是否有父级再进行删除修复了这个问题,因为碰撞运行了多次。 - Gadget Blaster
哦,是的。我还设置了 skView.shouldCullNonVisibleNodes = false; 因为我的游戏逻辑处理所有节点的删除。 - Gadget Blaster
卡尔说的帮了我很多,再也没有在iOS 8上崩溃了。 - RyanG
1个回答

3

我在iOs8的枚举中遇到了一个问题:

[supers enumerateChildNodesWithName:@"super3" usingBlock:^(SKNode *node, BOOL *stop) {
 ....
            [supers addChild:super3counter]; //crash here
}]; 

dispatch_async也有帮助。

请注意:崩溃不会立即发生 - 大约需要0.5秒,而且代码在之前和之后甚至可以被执行。


实际上,由于SpriteKit运行循环在不同的线程上运行(可能是主线程),因此崩溃并不会立即发生,正如您所提到的那样,额外的代码行可能会在崩溃之前执行。 - giorashc
1
如何调试并找到崩溃点?除了手动注释操作,还有谁知道其他方法?.. :( - djdance
你们解决了吗?我也遇到了崩溃的问题。 - Steven Ritchie
2
Steven,首先不要在物理模拟器中删除/添加右侧,其次-尝试在枚举中查找删除/添加,第三-在碰撞函数中。我没有遇到其他崩溃情况。您可以通过更新功能或通过调度来删除/添加。 - djdance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接