Manual retain with ARC
Asked Answered
M

3

25

Before ARC I had the following code that retains the delegate while an async operation is in progress:

- (void)startAsyncWork
{
    [_delegate retain];
    // calls executeAsyncWork asynchronously
}

- (void)executeAsyncWork
{
    // when finished, calls stopAsyncWork
}

- (void)stopAsyncWork
{
    [_delegate release];
}

What is the equivalent to this pattern with ARC?

Mcniel answered 17/10, 2011 at 10:46 Comment(0)
C
10

Why not just assign your delegate object to a strong ivar for the duration of the asynchronous task?

Or have a local variable in executeAsyncWork

- (void)executeAsyncWork
{
    id localCopy = _delegate;

    if (localCopy != nil) // since this method is async, the delegate might have gone
    {
        // do work on local copy
    }
}
Chromite answered 17/10, 2011 at 10:52 Comment(3)
Thank you. That was my first idea too. I was hoping there would be another neat trick ;-).Mcniel
@hypercrypt: GCD is not a solution to making the variable hang around but it is a particularly nice way to actually do the async work.Chromite
@hypercrypt: I know GCD, but it's not the solution here ;-). I'm working with a NSURLConnectionDelegate.Mcniel
K
32

I have occasionally needed to manually retain and release things (sometimes just for debugging) and came up with the following macros:

#define AntiARCRetain(...) void *retainedThing = (__bridge_retained void *)__VA_ARGS__; retainedThing = retainedThing
#define AntiARCRelease(...) void *retainedThing = (__bridge void *) __VA_ARGS__; id unretainedThing = (__bridge_transfer id)retainedThing; unretainedThing = nil

This works by using the __bridge_retained and __bridge_transfer to cast things to and from (void *) which causes things to be retained, or to create a strong reference without calling retain.

Have fun, but be careful!

Kishke answered 29/3, 2013 at 16:17 Comment(4)
What is the reason for this part of the first macro: retainedThing = retainedThing?Preoccupy
that was my method of keeping the compiler from generating a warning about an unused variable.Kishke
This makes me weep with joy. After some work swizzling and fiddling with NSInvocations it became clear that my return value wasn't being retained long enough to make it back to the caller, so my pile of hacks gained two more hacks. Thanks you so much.Vidovic
This is exactly the solution I wanted, but it doesn't work for me. I get "Expected expression" and "Use of undeclared identifier "retainedThing" compiler errors.Tapia
C
10

Why not just assign your delegate object to a strong ivar for the duration of the asynchronous task?

Or have a local variable in executeAsyncWork

- (void)executeAsyncWork
{
    id localCopy = _delegate;

    if (localCopy != nil) // since this method is async, the delegate might have gone
    {
        // do work on local copy
    }
}
Chromite answered 17/10, 2011 at 10:52 Comment(3)
Thank you. That was my first idea too. I was hoping there would be another neat trick ;-).Mcniel
@hypercrypt: GCD is not a solution to making the variable hang around but it is a particularly nice way to actually do the async work.Chromite
@hypercrypt: I know GCD, but it's not the solution here ;-). I'm working with a NSURLConnectionDelegate.Mcniel
H
3

Something like this:

- (void)startAsyncWork
{
    id<YourProtocol> delegate = _delegate;
    dispatch_async(/* some queue */, ^{
        // do work
        [delegate doSomething];
    }
}

The block will retain the delegate as long as needed...

Helenehelenka answered 17/10, 2011 at 11:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.