views:

118

answers:

3
-(void)invokeMethod
{
    NSMethodSignature * sig = [[source class] instanceMethodSignatureForSelector:@selector(mySelector:)];
    NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:sig];

    [invocation setTarget:myTarget];
    [invocation setSelector:@selector(mySelector:)];

    MySubClassOfNSInvocationOperation * command = [[[MySubClassOfNSInvocationOperation alloc] initWithInvocation:invocation] autorelease];

    //setArgument retains command
    [invocation setArgument:&command atIndex:2];

    //addOperation retains command until the selector is finished executing
    [operationQueue addOperation:command];
}


-(void)mySelector:(MySubClassOfNSInvocation*)command
{
    //Do stuff
}

I don't know exactly what is happening, but NSInvocation & MySubClassOfNSInvocationOperation are leaking

When I remove the line:

[invocation setArgument:&command atIndex:2];

It doesn't leak, so some kind of problem with passing command as an argument.

A: 

It seems that setArgument method retains buffer (in this case - your command object). You can try to release command after setting. But you should be care). My friend was confused when his app wasn't run on new iPhone OS, because he corrected Apple's leak by adding one line with additional release message. And when apple made correction in new OS, this line was the reason of crashing the app)

Morion
Thanks for the response, but tried that, it ends up being dealloc'd twice and crashes.
Ben Reeves
A: 

What's with the extra ampersand on this line:

[invocation setArgument:&command atIndex:2];

You're passing a pointer-to-a-pointer of your command. That seems wrong to me.

JBRWilkinson
Nope – that's right http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html#//apple_ref/occ/instm/NSInvocation/setArgument:atIndex:
Perspx
Specifically "When the argument value is an object, pass a pointer to the variable (or memory) from which the object should be copied:"
Perspx
My bad - I stand corrected.
JBRWilkinson
+2  A: 

You probably have a reference counted loop... a situation where command retains invocation and invocation retains command and neither wants to release until their own dealloc method -- leading to a situation where they never get freed.

You need to decide which of the two is hierarchically senior to the other and make sure that the junior object does not retain the senior. Incidentally -- NSInvocation won't retain arguments unless you call retainArguments. Alternately, you can implement a close method, manually telling one to release the other, breaking the cycle.

I wrote the post "Rules to avoid retain cycles" after uncovering this exact issue with NSInvocation in one of my own projects.

Matt Gallagher
Perfect. Thanks
Ben Reeves