When do I release this block? - objective-c

I was looking at some code in this thread How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?. I was wondering, if the block does something asynchronously, when should the block be released?
Let's say I have code that looks like this:
- (void)testMethod:(id)parameter
{
dispatch_block_t block = ^{
SomeAsyncTask *t = [SomeAsyncTask withCompletionBlock:^{
[parameter doAction];
}];
};
[self performSelector:#selector(executeBlock:)
onThread:backgroundThread
withObject:block
waitUntilDone:NO];
dispatch_release(block); //I can release the block here because performSelector retains the block
}
- (void)executeBlock:(id)block
{
block();
}
Is the key then, that the completion block in SomeASyncTask will retain the parameter so it's safe to release the block?

Ken Thomases's answer is correct. I want to give a more detailed response to your comments.
First, it is not clear whether you meant performSelector:withObject: or performSelector:withObject:afterDelay:, since performSelector:withObject: is a direct synchronous call, so [self performSelector:#selector(runBlock:) withObject:block_]; is identical to [self runBlock:block_]. I'll assume it's performSelector:withObject:afterDelay:, since performSelector:withObject: is less interesting.
Look at it step by step. performSelector:withObject:afterDelay: retains its argument, so you can release it after giving the block to it. And performSelector:... retains it through the performance of its selector. So during the runBlock, the block is valid because it is still retained by performSelector:.... During the execution of the block, it is still valid (since it is still inside the execution of runBlock). doSomethingAsynchronouslyWithCompletionBlock must retain its argument if it is asynchronous. And so on.
But you don't need to look at it that way. Once you think through it, you will realize that the memory management rules are made so that you don't need to worry about what other code does, only what you need locally.
The memory management rules boil down to the following conditions: Every function / method expects its arguments to be valid when it is called (which usually means through the duration of the function call, since the calling function does not run during this time, so how can it become invalid, unless this function does something which indirectly removes it (like removing from a dictionary)?); and does not have any expectations about how long it will remain valid after the function call. That's it. Everything follows from this.
For example, in your doWork, you only care about how long you need to use the block. Since you don't need it after performSelector:..., you can safely release it. It doesn't matter that performSelector:... might do something with it asynchronously; you may not even know that it is asynchronous (e.g. you could be choosing an unknown method to call dynamically). The point is, what it does doesn't matter. Why? Because the performSelector:... does not assume the argument to be valid any longer than when you called it. So if it needs to keep it longer (and it does), it must retain it (but you don't need to know this). And it will retain it for as long as it needs it.
Similarly, runBlock can assume that the argument it was given is valid for the duration of its call. Since it does not need to keep it around for longer (all it does is call the block), it does not need to retain it. The block does not change this. Why? Again, because the block does not assume its arguments (including the block itself) is valid after its call, so runBlock doesn't need to guarantee it. If the block calls doSomethingAsynchronouslyWithCompletionBlock, that's fine. doSomethingAsynchronouslyWithCompletionBlock does not assume anything is valid beyond its call, so if it is truly asynchronous, it must retain it somewhere. etc.

You can release it immediately after invoking -performSelector:withObject:afterDelay:. (I assume you meant to use the after-delay variant.) As usual, you are responsible for your memory management and other code is responsible for its memory management. Which is another way of saying that -performSelector:withObject:afterDelay: has to retain the receiver and the object that's passed in until after the selector has been performed.
Edited to add: By the way, why wouldn't you use dispatch_after() as illustrated in the answer to the question to which you linked?

I might just try passing an array with the arguments.

Related

In Objective-c is performSelector executed inline or is it posted for execution as a different event?

There are plenty of reasons why this matters. Here's a simple example if you weren't using ARC.
[instance performSelector:selector withObject:objectA];
[objectA release]; // Did the selector actually finish executing
// in the line above so everyone's done with objectA
// or did the selector merely get scheduled in the line
// above, and is yet to execute, so objectA had better
// not be released yet?
I've done some research and context clues seem to point to selector getting done inline. But I haven't seen any definitive statement anywhere I've looked, that states it gets executed inline.
performSelector:withObject: is executed synchronously (block until the method finished).
Use performSelector:withObject:afterDelay: to execute method asynchronously on main thread (return immediately and execute later).
Use performSelectorInBackground:withObject: to execute method asynchronously on background thread (return immediately and execute on different thread).
Note:
performSelector and its friends should be avoid because it is undefined behaviour if you use them on method with incompatible method signature.
The aSelector argument should identify a method that takes no arguments. For methods that return anything other than an object, use NSInvocation.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/index.html#//apple_ref/occ/intfm/NSObject/performSelector:
Did the selector actually finish executing in the line above so
everyone's done with objectA or did the selector merely get scheduled
in the line above, and is yet to execute, so objectA had better not be
released yet?
It doesn't matter, for memory management purposes. Memory management in Cocoa is local -- you only need to care what your function does; you don't need to know, and shouldn't care, what other functions do internally, to manage memory correctly (ignoring retain cycles). As long as you're done with your owning reference, you should release it. It doesn't matter to you if other people are done with it.
This is because, according to Cocoa memory management rules, any function which needs to store it for use beyond the function call is required to retain it and release it when it's done (because the function cannot assume that the object lives beyond the calling scope otherwise). Any function which uses an argument asynchronously (e.g. performSelector:withObject:afterDelay: etc.) does indeed retain the object and release it when it's done.
Alternately, think about it this way: How does ARC work? How does ARC know whether a function uses its argument synchronously or asynchronously? It doesn't. There is no annotation that tells the compiler whether a function uses something synchronously or asynchronously. Yet ARC does it correctly. That means you can too, without knowing whether the function uses its argument synchronously or asynchronously.

Should I retain the argument with GCD dispatch_X (or does it retain it)

As far as I remember we had something like performSelectorOnMainThread: (and variants) do retain the objects until the method is finished executing" in Apple's documentation. So can we rely on such behavior in ios6? Cause there isn't any info in the NSObject Class Reference now. The same question in case I prefer using GCD dispatch_async/sync - if I have object created in back thread - should I choose dispatch_sync(dispatch_get_main_queue) to be sure that object won't be released until selector executes.
The thing about the Cocoa memory management system is that you NEVER have to care about this. Memory management is completely local -- you never care about what other functions do. The basic rule is -- the caller guarantees that an object argument is valid when the function is called, and does not guarantee anything else.
If a function somehow stores an object for use later, it MUST (by deduction) retain it somehow, since it does not assume that the object is valid for any longer. Conversely, as a caller of the function, you don't need to think about what a function does or whether it does something asynchronously or not, because you are not guaranteeing to the function that its argument is alive at any point after it's called.
blocks, which GCD dispatch capture their context: In this case this means they retain everything they reference until executed :)

What's the difference between NSInvocation and block?

when i say block i mean:
^(int a) {return a*a;};
besides, block is only support by iOS4 and above.
What is the difference between these two?
An NSInvocation is a message (using a selector) to an object, with optional parameters, which can be executed later (or now), and outside the current context (mind of course what you copy vs retain or reference if you move it). NSInvocation has the benefit that you can selectively copy/refer to exactly what you need.
The block is a secret local function definition, which is able to capture portions of the current thread's context, or altogether. It's also a little easier to configure than an NSInvocation because it automatically captures, copies, and retains the thread (or scope) local context. Blocks can increase your binary size slightly, similar to functions. If taken out of the local context (e.g. when you copy a block), blocks can require quite a bit more CPU time and memory - when compared to NSInvocation.
NSInvocation is an object that encapsulates a message call: the target object, the selector, the arguments and the return value. A block is an object that encapsulates a section of code and some information about the state of the program leading up to that section: specifically it records the variables on the call stack up to the creation of the block.
Both of these can clearly be used as callbacks: you can use an invocation to send a message to an object, or you can execute a block's code just like a function. What's different about them is the way you'd transport state in each case. With an invocation, you either need the target object or one of the parameters to represent the context in which the message is appearing. With a block, this context is captured automatically from the state when the block was created.
To put it very simply, NSInvocation is less powerful than blocks. It just encapsulates a single method call on a single object, whereas blocks can wrap many lines of arbitrary code. Even your very simple squaring block is impossible to represent using an invocation without support from an existing class that would do the squaring itself.

Must I copy a block here?

I understand that you must copy blocks in order for them to stick around after a stack frame exits. But, how does that apply to stack-allocated blocks used within a nested block as in the following code example:
- doSomethingFunkyThenCall:(void(^)(int someValue))callback
{
[[NSOperationQueue currentQueue] addOperationWithBlock:^{
// ... do some work here, potentially nesting into further blocks ...
callback(result);
}];
}
Obviously, the doSomethingFunkyThenCall: stack frame will terminate before the callback is executed, so it will have to be copied. But will this happen automatically in the call to addOperationWithBlock: or do I have to do it manually?
Most likely, it will happen automatically. Cocoa's design principles imply in general that you're not responsible for objects (their memory management, passing blocks [which are, in fact, implemented as proper Objective-C objects], etc.) you haven't created. So you can just pass down the block you received as a parameter, and the runtime will manage it as per its needs.
Yes, you should do a callback = [[callback copy] autorelease]; at the top of this method.
Objects used in blocks are retained automatically, but sending a stack-block retain actually does nothing (because the semantics of retain require it to return the receiver), so will be gone once we leave the frame it was created in.
Sources:
http://cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html
http://thirdcog.eu/pwcblocks/#objcblocks
EDIT: It turns out I'm wrong. #bbum points out below that Block_copy will copy recursively, and since addOperationWithBlock: copies it's block, the callback is also copied.

Objective C: Memory management in Block cases

I am wondering if I am using blocks as shown in the code below
__block Loader *loader = [[Loader alloc]initWithResourcePath:self.resourcePath];
[loader setCompletionHandler:^(NSArray *anArray){
self.answerArray=anArray;
[self reloadData];
}];
[loader getObjects];
My question is with regards to memory management. The analyzer tells me that there is a potential leak (since I did an alloc/init for my loader). How can I stop the leak here? I tried to release the loader at the end but that causes my app to stop functioning. Any advise is appreciated here
Several issues:
there is no reason for loader to be declared __block; you aren't re-assigning in the block and, thus, the __block is pointless.
the leak is because you alloc/init the loader, but never release it
do not name methods getSomething; the get prefix is reserved for methods that return stuff by reference. Just call it objects. If it is supposed to trigger the load, then call it load or performLoad.
If it is asynchronous, then getObjects is pointless. If synchronous, then the completion block is pointless.
If loader is to be used synchronously, release it at the end of the method. If it is asynchronous, then the completion block could release it. Note that the use of __block in this case is still pointless; while referring to loader in the completion block will create a retain cycle, it will be broken when you explicitly Block_release() the block in your loader (because you must have done a Block_copy() when setting the completion handler if it is to be used asynchronously in the first place).
If you plan to use loader outside of the function calling your block, it is highly possible that you need to store it in a ivar of your controller (I guess, it is a controller, but I don't know what kind of class owns the code you shows). Once you do that, you can release it in your dealloc.
The reasoning is that loader should live across several methods and runloop cycles, so a local variable will not do.
Otherwise, just release it at the end of the block, once you have done with it.
If this does not seem right to you, then possibly more code is needed.
I'm going to make some assumptions: 1) The completion handler (block) is used by method getObjects. 2) getObjects is asynchronous (it returns to the caller right away though it continues to process).
With these assumptions you can't send release after sending getObjects because getObjects is still using the completion handler.
Try sending a release or autorelease at the end of the completion handler. That should free loader provided reloadData is not also asynchronous.