7

In my applicationDidFinishLaunching: method, I create an object and call an asynchronous method on it, like so:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    Foo *foo = [[Foo alloc] init];

    [foo asynchronousMethodWithCompletion:^{
        // Location A
    }];

    // Location B
}

If I do not use ARC, where do I have to put [foo release]? Inside the completion block (Location A) or right after the asynchronous method call (Location B)? Or doesn't it matter at all?

tajmahal
  • 1,665
  • 3
  • 16
  • 29

1 Answers1

7

You put [foo release] at Location B, like you normally would do if there was a regular method call instead of the block. The block will retain the object and release it after it is done.

Davyd Geyl
  • 4,578
  • 1
  • 28
  • 35
  • Will the block do so even if it is only stack-based? Or will I have to do `[block copy]` in `asynchronousMethodWithCompletion:`? Does it matter whether I put `__block` in front of `Foo *foo = [[Foo alloc] init];`? – tajmahal Nov 26 '12 at 05:25
  • This is a whole lot of new questions. In your example you do not need to copy the block. Also, you do not need to use `__block` keyword because it will prevent `foo` from retaining. Read Blocks and Variables: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html Also check http://stackoverflow.com/questions/7080927/what-does-the-block-keyword-mean. If you still have questions open new once. – Davyd Geyl Nov 26 '12 at 09:22
  • 2
    @tajmahal: The block will only retain `foo` if it is copied. But the block is guaranteed to be copied if it outlives the call. Whether you have to write `copy` in `asynchonousMethodWithCompletion:` depends on how it is written (you have not shown us the code). You need to copy it before it is stored for later e.g. in an instance variable or in a general container; if it is simply passed to another function which takes a block argument, then no, it doesn't need to be copied, because *that* function is responsible for copying it if it needs to store it for later. – newacct Nov 26 '12 at 16:31
  • @newacct: I read somewhere that when a stack-based block goes out of scope, it simply gets deallocated. Is that not true? Anyways, your comment did help me get a better understanding of blocks, thanks! – tajmahal Nov 26 '12 at 20:17
  • @tajmahal: yes, that is true – newacct Nov 26 '12 at 21:42
  • @newacct: But doesn't that contradict you saying "But the block is guaranteed to be copied if it outlives the call."? – tajmahal Nov 26 '12 at 22:21
  • @tajmahal: No, whatever function or method stores the block in a place that outlives the call, must store a copy of the block. – newacct Nov 26 '12 at 23:01
  • I'm still having some problems understanding this. In my above example, `asynchronousMethodWithCompletion:` will return immediately. So the block will still be executing when `applicationDidFinishLaunching:` has returned, but nobody will have a reference to it. Hasn't the block now gone out of scope, causing it to be deallocated immediately, even though it is currently executing If not, what is meant by "a block goes out of scope"? – tajmahal Nov 26 '12 at 23:59
  • @tajmahal: The object `foo` may copy the block and release it after it is done with it. If the `Foo` is not your class, do not worry it will take care of it. If you write the `Foo` class yourself then you may need to copy the given block inside the `asynchronousMethodWithCompletion` method and release it after you finished with it. This would depend on how you are going to use the given block inside your class, as newacct has already said. – Davyd Geyl Nov 27 '12 at 00:44
  • `Foo` is my own class. In `asynchronousMethodWithCompletion:`, I create an `NSURLConnection`, assign the block to an instance variable (say, `x`), and call it when `NSURLConnection`s delegate methods get called. So I'd have to do `x = [block copy];` in it at the beginning and `[x release];` at the end? But that means a stack-based block doesn't do anything such as automatically retain objects it uses, and as soon as I copy it, the objects are automatically retained until I release the block again? Then I got it, I think. – tajmahal Nov 27 '12 at 06:14
  • 2
    @tajmahal: Like I said, if the `asynchronousMethodWithCompletion:` stores the block (as you do, in an instance variable), then it needs to store a copy of the block (as you do, with `x = [block copy];`, and you need to release it when `Foo` is deallocated or `x` is re-assigned, as with all object instance variables) If, instead, your `asynchronousMethodWithCompletion:` simply calls something like `dispatch_async()` with the block and doesn't store it itself, then it doesn't need to copy it. "the objects are automatically retained until I release the block again?" until the block is deallocated – newacct Nov 27 '12 at 20:42