SpriteKit: NSInvalidArgumentException - 试图添加一个已经有父节点的 SKNode

Posted

技术标签:

【中文标题】SpriteKit: NSInvalidArgumentException - 试图添加一个已经有父节点的 SKNode【英文标题】:SpriteKit: NSInvalidArgumentException - Attempted to add a SKNode which already has parent 【发布时间】:2014-09-29 06:47:33 【问题描述】:

我正在使用 Objective-C 在 SpriteKit 中创建一个游戏。我正在尝试为要在游戏中使用的屏幕生成块。

我在启动时遇到应用程序崩溃:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attemped to add a SKNode which already has a parent: <SKSpriteNode> name:'Block-0.000000-440.000000' texture:['nil'] position:0, 440 size:64, 64 rotation:0.00'
*** First throw call stack:
(
    0   CoreFoundation                      0x00891df6 __exceptionPreprocess + 182
    1   libobjc.A.dylib                     0x0051ba97 objc_exception_throw + 44
    2   CoreFoundation                      0x00891d1d +[NSException raise:format:] + 141
    3   SpriteKit                           0x00e8c94c -[SKNode addChild:] + 119
    4   Hidden Route                        0x0003b3c1 -[GameScene didMoveToView:] + 2417
    5   SpriteKit                           0x00e6031b -[SKScene _didMoveToView:] + 97
    6   SpriteKit                           0x00e7b157 -[SKView presentScene:] + 283
    7   Hidden Route                        0x00039e9e -[GameViewController viewDidLoad] + 526
    8   UIKit                               0x0115ad54 -[UIViewController loadViewIfRequired] + 771
    9   UIKit                               0x0115b045 -[UIViewController view] + 35
    10  UIKit                               0x0105f477 -[UIWindow handleStatusBarChangeFromHeight:toHeight:] + 879
    11  UIKit                               0x0106252d +[UIWindow _noteStatusBarHeightChanged:oldHeight:forAutolayoutRootViewsOnly:] + 273
    12  UIKit                               0x01006ad1 __79-[UIApplication _setStatusBarHidden:animationParameters:changeApplicationFlag:]_block_invoke + 163
    13  UIKit                               0x010862c6 +[UIView(UIViewAnimationWithBlocks) _setupAnimationWithDuration:delay:view:options:factory:animations:start:animationStateGenerator:completion:] + 494
    14  UIKit                               0x01086701 +[UIView(UIViewAnimationWithBlocks) animateWithDuration:animations:completion:] + 115
    15  UIKit                               0x0100699e -[UIApplication _setStatusBarHidden:animationParameters:changeApplicationFlag:] + 506
    16  UIKit                               0x01006128 -[UIApplication _updateCurrentStatusBarViewControllerAppearance] + 286
    17  UIKit                               0x0105223a -[UIWindow _updateContextOrderingAndSetLayerHidden:] + 548
    18  UIKit                               0x0105319e -[UIWindow _setHidden:forced:] + 257
    19  UIKit                               0x01053473 -[UIWindow _orderFrontWithoutMakingKey] + 49
    20  UIKit                               0x01061615 -[UIWindow makeKeyAndVisible] + 80
    21  UIKit                               0x00ffecd6 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3108
    22  UIKit                               0x0100216d -[UIApplication _runWithMainScene:transitionContext:completion:] + 1639
    23  UIKit                               0x0101ad30 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke + 59
    24  UIKit                               0x01000d7f -[UIApplication workspaceDidEndTransaction:] + 155
    25  FrontBoardServices                  0x06f909de __37-[FBSWorkspace clientEndTransaction:]_block_invoke_2 + 71
    26  FrontBoardServices                  0x06f9046f __40-[FBSWorkspace _performDelegateCallOut:]_block_invoke + 54
    27  FrontBoardServices                  0x06fa2425 __31-[FBSSerialQueue performAsync:]_block_invoke + 26
    28  CoreFoundation                      0x007b57a0 __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 16
    29  CoreFoundation                      0x007ab0b3 __CFRunLoopDoBlocks + 195
    30  CoreFoundation                      0x007aaf0b __CFRunLoopRun + 2715
    31  CoreFoundation                      0x007aa1ab CFRunLoopRunSpecific + 443
    32  CoreFoundation                      0x007a9fdb CFRunLoopRunInMode + 123
    33  UIKit                               0x01000744 -[UIApplication _run] + 571
    34  UIKit                               0x01003e16 UIApplicationMain + 1526
    35  Hidden Route                        0x0003c41d main + 141
    36  libdyld.dylib                       0x02fa0ac9 start + 1
    37  ???                                 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

我查看了堆栈跟踪,发现导致问题的方法是我的didMoveToView: 方法,它是这样的:

-(void)didMoveToView:(SKView *)view

    // ViewDidLoad
    [self initialize];

    /* Setup your scene here
    SKLabelNode *myLabel = [SKLabelNode labelNodeWithFontNamed:@"Arial"];

    myLabel.text = @"Hello, World!";
    myLabel.fontSize = 65;
    myLabel.position = CGPointMake(CGRectGetMidX(self.frame),
                                   CGRectGetMidY(self.frame));
    */
    player = [SKSpriteNode spriteNodeWithColor:[AppDelegate getRandomColor] size:CGSizeMake(40, 40)];
    player.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

    [self generateBoard];
    [self generateNextAtIndex:kNeed - 3];

    int width = (self.frame.size.width) / [AppDelegate numberOfColumns];
    int height = (self.frame.size.height) / kNeed;


    for (int i = 0; i < boardRows.count; i++)
    
        Row *current = [boardRows objectAtIndex:i];

        for (int j = 0; j < current.blocks.count; j++)
        
            Block *block = [current.blocks objectAtIndex:j];

            block.anchorPoint = CGPointMake(0, 1);
            block.position = CGPointMake((j * width), self.frame.size.height - (i * width));
            [block setName:[NSString stringWithFormat:@"Block-%f-%f", block.position.x, block.position.y]];

            NSLog(@"Position for item %i", i);

            block.size = CGSizeMake(width, width);

            [self addChild:block];
        
    


    [self addChild:player];

我觉得这与self addChild:block 行有关,但我无法找到解决方案。如果您需要更多信息,我会在此处发布(只需索取)

感谢您的帮助

编辑 1:

generateBoard方法:

- (void)generateBoard

    int rnd = 2;

    int from = rnd;
    int to = 0;

    Row *row = [defaultRows objectAtIndex:rnd];
    [boardRows replaceObjectAtIndex:0 withObject:row];

    for (int i = 2; i < boardRows.count; i++)
    
        rnd = arc4random() % [AppDelegate numberOfColumns];
        to = rnd;

        Row *rowThis = [defaultRows objectAtIndex:rnd];

        Row *rowBelow = [[Row alloc] initWithSize:CGSizeMake(self.frame.size.width, self.frame.size.height) need:kNeed];

        [rowBelow generateWithPoint:from toPoint:to];

        [boardRows replaceObjectAtIndex:i withObject:rowThis];
        [boardRows replaceObjectAtIndex:i-1 withObject:rowBelow];

        to = from;
        from = rnd;

        // to make it add 2
        i++;
    

编辑 2:

添加异常断点后,发现导致问题的行是self addChild:block

【问题讨论】:

添加异常断点。发布生成板方法。 boardRows 不能两次包含相同的节点 什么是异常断点?现在添加 generateBoard 方法 developer.apple.com/library/ios/recipes/… 【参考方案1】:

这个问题的答案很简单,基本上我有一些预先配置的块来简化生成,但是在这样做时,调用self addChild:block实际上是试图将相同的块(具有相同的内存地址)添加到 2一次放置,因此导致应用程序崩溃。

我刚刚在我的 Block 类中添加了一个重复的函数并开始实现它,而不是直接调用该块。

【讨论】:

以上是关于SpriteKit: NSInvalidArgumentException - 试图添加一个已经有父节点的 SKNode的主要内容,如果未能解决你的问题,请参考以下文章

使用 NSFilemanager 存储 NSMutableArray 时崩溃

Spritekit - 屏幕坐标的底部

Spritekit - 屏幕坐标的底部

SpriteKit - 暂停输入

SpriteKit 暂停和恢复 SKView

CAShapeLayer 和 SpriteKit