Get block argument from NSInvocation with ARC
Asked Answered
N

1

13

I'm trying to get the block argument from the NSInvocation in NSProxy's forwardInvocation: Is this the correct syntax? Would it leak memory?

typedef void(^SuccessBlock)(id object);
void *successBlockPointer;
[invocation getArgument:&successBlockPointer atIndex:index];
SuccessBlock successBlock = (__bridge SuccessBlock)successBlockPointer;

Or should I use?

typedef void(^SuccessBlock)(id object);
SuccessBlock successBlock;
[invocation getArgument:&successBlock atIndex:index];

What about other argument types like objects?

__unsafe_unretained id myObject = nil; // I don't think this could be __weak? Is that correct?
[invocation getArgument:&myObject atIndex:index];

Do I have to do anything else to correctly free up allocated memory?

Thanks in advance.

Nole answered 4/6, 2013 at 22:4 Comment(0)
M
13

Yes. Under ARC, it is incorrect to use

id myObject = nil; // or any object type or block type
[invocation getArgument:&myObject atIndex:index];

because &myObject is type id __strong *, i.e. pointer to strong reference. Whoever assigns to the strong reference pointed to by this pointer must take care to release the previous value and retain the new value. However, getArgument:atIndex: does not do that.

You are right. The two correct ways to do it you have already found: 1) do it with void * and then assign it back into object pointer, or 2) do it with __unsafe_unretained object pointer.

Methadone answered 5/6, 2013 at 6:16 Comment(11)
And, I'm assuming neither approach leaks memory? Instruments is not reporting any leaks. Is one approach preferred over the other for blocks or other objects (non-block objects)?Nole
@pshah: Yes, both approaches are correct memory-wise. I prefer the __unsafe_unretained but there is no difference.Methadone
Do I need to copy these blocks when they are passed in as parameters? From what I understand, blocks need to be explicitly copied when they are passed in as id parameters. I have a strongly-typed interface (not id) for the block which eventually invokes forwardInvocation:. Can I copy the block somehow in forwardInvocation: itself?Nole
@pshah: What do you mean "when they are passed in as parameters"? Whether you need to copy the block here in forwardInvocation: depends on what you do with it. If you simply invoke the invocation or pass it on synchronously to a method which takes a block parameter, then no. If you need to store it somehow, then yes.Methadone
I have a method like - (void)someMethod:(SuccessBlock)block; This method is not implemented and invokes forwardInvocation:. I get the block in forwardInvocation: using getArgument:atIndex: This block is passed to a method (as an argument) that asynchronously makes a network result and eventually invokes the block. If I don't copy the block and pass it to someMethod:, the app crashes. I was wondering if there is a way to "copy" the block within forwardInvocation: itself so that every method like someMethod: doesnt have to copy it.Nole
@pshah: well, does that second method take a block parameter?Methadone
Yeah. The flow is someMethod: -> forwardInvocation: -> httpRequest: where someMethod: and httpRequest: both take the block as an argumentNole
@pshah: well, if the second method takes a block parameter, and it is invoked synchronously by forwardInvocation:, then you do not need to worry about copying blocks because that is the responsibility of the called method with block parameters (httpRequest:)Methadone
I thought so too. But, if I don't copy the block before passing it to someMethod: the app crashes. It seems like the block gets dealloced by the time httpRequest: tries to make use of it.Nole
@pshah: The problem with blocks is not that they're deallocated; but stack blocks are no longer valid after the scope they're defined in. If you're calling someMethod: (and thus forwardInvocation:) directly, then it should work okay. Unless you're doing something funny in forwardInvocation: like doing something asynchronous or something like that. You better start a new question because it's impossible to diagnose this without seeing some code.Methadone
I posted a new question with a link to complete source code here: #17607302Nole

© 2022 - 2024 — McMap. All rights reserved.