0

我有一个名为 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]];

请注意,我使用 [message copy],尽管我也尝试过仅使用消息。

4

1 回答 1

3

我闻到不好的做法:

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);
}];

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

于 2012-04-06T20:40:25.737 回答