【问题标题】:Cocos2D: EXC_BAD_ACCESS when using NSMutableString in CCCallFuncND actionCocos2D:在 CCCallFuncND 动作中使用 NSMutableString 时出现 EXC_BAD_ACCESS
【发布时间】:2012-04-06 20:17:17
【问题描述】:

我有一个名为 message 的 NSMutableArray,我已在 init 中分配并在 dealloc 中释放。我通常可以毫无问题地在 CCCallFuncND 操作中使用字符串,即使它是数组的索引,例如:

displayMessagePiece = [CCCallFuncND actionWithTarget:self selector:@selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain]];

但是,如果我使用我的可变字符串,我会遇到一个崩溃,一个绿色箭头指向我拥有它的代码行,并且它显示带有一些十六进制的“EXC_BAD_ACCESS”。

这是我尝试使用 NSMutableString 的操作和顺序:

id displayMessage = [CCCallFuncND actionWithTarget:self selector:@selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[message copy]] retain]];

[self runAction:[CCSequence actions:displayMessage,nil]];

请注意,我使用 [消息复制],虽然我也尝试过仅消息。

【问题讨论】:

    标签: nsstring cocos2d-iphone action sequence nsmutablestring


    【解决方案1】:

    我闻到了不好的做法:

    NSString* s = [[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain];
    [CCCallFuncND actionWithTarget:self 
                          selector:@selector(displayMessageBoxString:data:)
                              data:s];
    

    首先,您保留了一个可能会或可能不会释放的字符串。不能保证 displayMessageBoxString 选择器会被调用。例如,运行 call func 操作的节点可能会在调用选择器之前从场景中移除,或者您可能会在调用选择器之前更改整个场景。在这两种情况下,您都会泄漏字符串。

    当有 CCCallFuncO 时,也没有理由使用 CCCallFuncND。当您的项目使用 ARC 时,CCCallFuncND 尤其有害。在这种情况下,您必须将对象桥接到 void*,此时 ARC 可能会简单地释放内存,正确地假设非 ARC 代码现在管理对象的内存。自动释放实际上可能也是如此,但我不能 100% 确定这一点。

    因此,首要任务是使用 CCCallFuncO 并重新测试您的问题是否消失。还要依赖自动释放,不要保留字符串,因为您将无法在所有情况下释放它。

    NSString* s = [NSString stringWithFormat:[labelPieces objectAtIndex:i]];
    [CCCallFuncO actionWithTarget:self 
                         selector:@selector(displayMessageBoxString:)
                           object:s];
    

    现在,如果您的最低目标是 iOS 4.0,那么您确实应该改用块。如果您同时需要发送者和对象,则尤其如此。该块可以访问本地范围,因此您可以在这种情况下使用最简单的 CCCallBlock 操作:

    NSString* s = [NSString stringWithFormat:[labelPieces objectAtIndex:i]];
    [CCCallBlock actionWithBlock:^void(){
        CCLOG(@"sender is: %@, string is: %@", self, s);
    }];
    

    瞧,所有问题都已解决,并保证不会导致任何内存泄漏。

    请注意,您也可以像这样编写不带 void() 的块:

    [CCCallBlock actionWithBlock:^{
        CCLOG(@"sender is: %@, string is: %@", self, s);
    }];
    

    我个人觉得提醒自己和其他人注意返回类型和参数很有帮助,即使没有。

    【讨论】:

    • 我正在释放它调用的方法中的字符串.. 所以这部分很好。在我阅读其余部分之前,只是想把它弄明白。抱歉,我应该在 OP 中提到这一点。
    • 感谢您提供的所有信息。使用CCCallBlock,它怎么知道你试图调用什么方法?
    • 我正在使用 CCCallFuncO,当我将 NSString 定义为消息可变字符串时,我仍然得到 EXC_BAD_ACCESS。这与 labelPieces 无关,因为它总是工作得很好。我需要传递一个 NSMutableString 的消息。
    • 我只是想将一个 NSString 设置为 NSMutableString 值。我发现使用可变字符串值调用该方法并不重要。这使它崩溃,以及各种不同的定义方式: NSString *s = [NSString stringWithString:[message copy]];
    • 我知道它为什么会崩溃。我通过执行此消息设置我的消息 = [NSMutableString stringWithString:[hummingChar setLabelFromCharState:charName]];在 init 中分配它而不是仅使用 setString 之后。用动作调用方法的方法的类型很有帮助,所以我会标记它是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-20
    • 1970-01-01
    • 2016-01-19
    相关资源
    最近更新 更多