I have an NSMutableArray called message that I’ve alloc’d in init and release in dealloc. I can usually use a string in a CCCallFuncND action without a problem, even if it’s an index of an array, such as:
displayMessagePiece = [CCCallFuncND actionWithTarget:self selector:@selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[labelPieces objectAtIndex:i]] retain]];
However, if I use my mutable string, I get a crash with a green arrow pointing to my line of code that I have it in, and it says “EXC_BAD_ACCESS” with some hexadecimal.
Here’s my action and sequence where I’m trying to use NSMutableString:
id displayMessage = [CCCallFuncND actionWithTarget:self selector:@selector(displayMessageBoxString : data:) data:[[NSString stringWithFormat:[message copy]] retain]];
[self runAction:[CCSequence actions:displayMessage,nil]];
Notice I use [message copy], although I’ve tried also just message.
I smell bad practice:
First of all you are retaining a string that you may or may not be releasing. There is no guarantee that the displayMessageBoxString selector ever gets called. For example, the node running the call func action may be removed from the scene before the selector is called, or you may be changing the entire scene before the selector is called. In both cases you will be leaking the string.
There’s also no reason to use CCCallFuncND when there’s CCCallFuncO. CCCallFuncND is particularly harmful when your project is using ARC. In that case you’d have to bridge cast the object to void*, at which point ARC might simply release the memory, rightfully assuming that non-ARC code now manages the object’s memory. The same may actually be true for autorelease, but I’m not 100% certain about that.
So first order of business is to use CCCallFuncO and re-test if your problem is gone. Also rely on autorelease, do not retain the string since you will not be able to release it in all cases.
Now if your minimum target is iOS 4.0, you should really be using blocks instead. This is particularly true if you need both sender and object at the same time. The block has access to the local scope, so you can use the simplest CCCallBlock action in this case:
Et voila, all problems solved and guaranteed not to cause any memory leaks.
Note that you can also write the block without void() like this:
Personally I find it helpful to remind myself and others about the return type and parameters, even if there are none.