44

Suppose Object A has a property:

@property (nonatomic, strong) Foo * bar;

Synthesized in the implementation as:

@synthesize bar = _bar;

Object B manipulates a Foo **, as in this example call from Object A:

Foo * temp = self.bar;
[objB doSomething:&temp];
self.bar = temp;
  • Can this, or something similar, be done legitimately?
  • What is the correct declaration for the doSomething: method?

Furthermore, suppose Object B may be deallocated before I have a chance to set the bar property (and thus take on ownership of the instance pointed to by temp) - How would I tell ARC to hand off an owning reference? In other words, if I wanted the following example snippet to work, how would I need to handle the ARC issues?

Foo * temp = self.bar;    // Give it a reference to some current value
[objB doSomething:&temp]; // Let it modify the reference
self.bar = nil;           // Basically release whatever we have
_bar = temp;              // Since we're getting back an owning reference, bypass setter
  • What aren't I thinking of?

EDIT

Based on @KevinBallard 's answer, I just want to confirm my understanding. Is this correct?

Object A:

@implementation ObjectA

@synthesize bar = _bar;

- (void)someMethod
{
    ObjectB * objB = [[ObjectB alloc] initWithFoo:&_bar];
    // objB handed off somewhere and eventually it's "doSomething" method is called.
}

@end

Object B:

@implementation ObjectB
{
    Foo * __autoreleasing * _temp;
}

- (id)initWithFoo:(Foo * __autoreleasing *)temp
{
    id self = [super init];
    if (self)
    {
        _temp = temp;
    }
    return self;
}

- (void)doSomething
{
    ...
    *_temp = [[Foo alloc] init]; 
    ...
}

@end

This creates a compile-time error: passing address of non-local object to __autoreleasing parameter for write-back

Steve
  • 31,144
  • 19
  • 99
  • 122

2 Answers2

148

ARC needs to know the ownership of an object reference so it can determine when to release it etc. For any variable (local, instance or global) ARC has rules for determining the ownership; either by inference or by an explicit attribute. This equates to the pre-ARC need for the programmer to track ownership.

But what happens if you have a reference to a variable? You could not (pre-ARC) yourself write code which accepted a reference to a variable and which would always work correctly regardless of the ownership of that variable - as you could not know whether you needed to release etc. I.e. you can not construct code which works for variable (in the sense of changing!) unknown ownership.

ARC faces the same problem and its solution is to infer, or accept an explicit attribute specifying, the ownership of referenced variable and then require the caller to arrange for a reference to a variable of appropriate ownership to be passed. This latter bit can require the use of hidden temporary variables. This is referred to as "least bad solution" in the specification and is termed "pass-by-writeback".

The first part of the question:

Foo * temp = self.bar;
[objB doSomething:&temp];
self.bar = temp;
  • Can this, or something similar, be done legitimately?

Yes, the code is fine by ARC. temp is inferred to be strong and some behind the scenes stuff happens to pass it by reference to doSomething:.

  • What is the correct declaration for the doSomething: method?
- (void) doSomething:(Foo **)byRefFoo

ARC infers byRefFoo to be of type Foo * __autoreleasing * - a reference to an autoreleasing reference. This is what is required by "pass-by-writeback".

This code is only valid because temp is a local. It would be incorrect to do this with an instance variable (as you found out in your EDIT). It is also only valid assuming the parameter is being used in standard "out" mode and any updated value has been assign when doSomething: returns. Both of these are because the way pass-by-writeback works as part of that "least bad solution"...

Summary: when using local variables they can be passed by reference for use in the standard "out" pattern with ARC inferring any required attributes etc.

Under The Hood

Instead of the Foo of the question we'll use a type Breadcrumbs; this is essentially a wrapped NSString which tracks every init, retain, release, autorelease and dealloc (well almost as you'll see below) so we can see what is going on. How Breadcrumbs is written is not material.

Now consider the following class:

@implementation ByRef
{
   Breadcrumbs *instance;                                // __strong inferred
}

A method to change a value passed by reference:

- (void) indirect:(Breadcrumbs **)byRef                  // __autoreleasing inferred
{
   *byRef = [Breadcrumbs newWith:@"banana"];
}

A simple wrapper for indirect: so we can see what it is passed and when it returns:

- (void) indirectWrapper:(Breadcrumbs **)byRef           // __autoreleasing inferred
{
   NSLog(@"indirect: passed reference %p, contains %p - %@, owners %lu", byRef, *byRef, *byRef, [*byRef ownerCount]);
   [self indirect:byRef];
   NSLog(@"indirect: returned");
}

And a method to demonstrate indirect: called on a local variable (called imaginatively local):

- (void) demo1
{
   NSLog(@"Strong local passed by autoreleasing reference");
   Breadcrumbs *local;                                   // __strong inferred
   local = [Breadcrumbs newWith:@"apple"];
   NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
   [self indirectWrapper:&local];
   NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
}

@end

Now some code to exercise demo1 localizing the autorelease pool so we can see what is allocated, released and when:

ByRef *test = [ByRef new];

NSLog(@"Start demo1");
@autoreleasepool
{
   [test demo1];
   NSLog(@"Flush demo1");
}
NSLog(@"End demo1");

Executing the above produces the following on the console:

ark[2041:707] Start demo1
ark[2041:707] Strong local passed by autoreleasing reference
ark[2041:707] >>> 0x100176f30: init
ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
ark[2041:707] indirect: passed reference 0x7fff5fbfedb8, contains 0x100176f30 - apple, owners 1
ark[2041:707] >>> 0x100427d10: init
ark[2041:707] >>> 0x100427d10: autorelease
ark[2041:707] indirect: returned
ark[2041:707] >>> 0x100427d10: retain
ark[2041:707] >>> 0x100176f30: release
ark[2041:707] >>> 0x100176f30: dealloc
ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100427d10 - banana, owners 2
ark[2041:707] >>> 0x100427d10: release
ark[2041:707] Flush demo1
ark[2041:707] >>> 0x100427d10: release
ark[2041:707] >>> 0x100427d10: dealloc
ark[2041:707] End demo1

[The ">>>" lines come from Breadcrumbs.] Just follow the addresses of the objects (0x100...) and variables (0x7fff...) and it is all clear...

Well maybe not! Here it is again with comments after each chunk:

ark[2041:707] Start demo1
ark[2041:707] Strong local passed by autoreleasing reference
ark[2041:707] >>> 0x100176f30: init
ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1

Here we see that [Breadcrumbs newWith:@"apple"] creates an object at address 0x100176f30. This is stored in local, whose address is 0x7fff5fbfedc0, and the object has 1 owner (local).

ark[2041:707] indirect: passed reference 0x7fff5fbfedb8, contains 0x100176f30 - apple, owners 1

Here comes the hidden variable: as indirect: requires a reference to an autoreleasing variable ARC has created a new variable, whose address is 0x7fff5fbfedb8, and copied the object reference (0x100176f30) into that.

ark[2041:707] >>> 0x100427d10: init
ark[2041:707] >>> 0x100427d10: autorelease
ark[2041:707] indirect: returned

Inside indirect: a new object is created and ARC autoreleases it before assigning it - because the passed references refers to an autoreleasing variable.

Note: ARC does not need to do anything with the previous contents (0x100176f30) of the referenced variable (0x7fff5fbfedb8) as it is autoreleasing and hence not its responsibility. I.e. what "autoreleasing ownership" means is that any reference assigned must have already been effectively autoreleased. You'll see when creating the hidden variable ARC did not actually retain and autorelease its contents - it did not need to do this as it knows there is a strong reference (in local) to the object which it is managing. [In the last example below ARC does have to manage this assignment but it still manages to avoid using the autorelease pool.]

ark[2041:707] >>> 0x100427d10: retain
ark[2041:707] >>> 0x100176f30: release
ark[2041:707] >>> 0x100176f30: dealloc

These actions result from copying (the "writeback" in call-by-writeback) the value from the hidden variable into local. The release/dealloc are for the old strong reference in local, and the retain is for the object referenced by the hidden variable (which was autoreleased by indirect:)

Note: this writeback is why this only works for the "out" pattern of using pass-by-reference - you can't store the reference passed to indirect: as it is to a hidden local variable which is about to disappear...

ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100427d10 - banana, owners 2

So after the call local refers to the new object, and it has 2 owners - local accounts for one, and the other is the autorelease in indirect:

ark[2041:707] >>> 0x100427d10: release

demo1 is now finished so ARC releases the object in local

ark[2041:707] Flush demo1
ark[2041:707] >>> 0x100427d10: release
ark[2041:707] >>> 0x100427d10: dealloc
ark[2041:707] End demo1

and after demo1 returns the localized @autoreleasepool handles the autorelease pending from indirect:, now the ownership is zero and we get the dealloc.

Passing instance variables by reference

The above deals with passing local variables by reference, but unfortunately pass-by-writeback does not work for instance variables. There are two basic solutions:

  • copy your instance variable to a local

  • add some attributes

To demonstrate the second we add to class ByRef a strongIndirect: which specifies it requires a reference to a strong variable:

- (void) strongIndirect:(Breadcrumbs * __strong *)byRef
{
   *byRef = [Breadcrumbs newWith:@"plum"];
}

- (void) strongIndirectWrapper:(Breadcrumbs * __strong *)byRef
{
   NSLog(@"strongIndirect: passed reference %p, contains %p - %@, owners %lu", byRef, *byRef, *byRef, [*byRef ownerCount]);
   [self strongIndirect:byRef];
   NSLog(@"strongIndirect: returned");
}

and a corresponding demo2 which uses ByRef's instance variable (again with the imaginative name of instance):

- (void) demo2
{
   NSLog(@"Strong instance passed by strong reference");
   instance = [Breadcrumbs newWith:@"orange"];
   NSLog(@"instance: addr %p, contains %p - %@, owners %lu", &instance, instance, instance, [instance ownerCount]);
   [self strongIndirectWrapper:&instance];
   NSLog(@"instance: addr %p, contains %p - %@, owners %lu", &instance, instance, instance, [instance ownerCount]);
}

Execute this with a similiar piece of code as for demo1 above and we get:

1  ark[2041:707] Start demo2
2  ark[2041:707] Strong instance passed by strong reference
3  ark[2041:707] >>> 0x100176f30: init
4  ark[2041:707] instance: addr 0x100147518, contains 0x100176f30 - orange, owners 1
5  ark[2041:707] strongIndirect: passed reference 0x100147518, contains 0x100176f30 - orange, owners 1
6  ark[2041:707] >>> 0x100427d10: init
7  ark[2041:707] >>> 0x100176f30: release
8  ark[2041:707] >>> 0x100176f30: dealloc
9  ark[2041:707] strongIndirect: returned
10 ark[2041:707] instance: addr 0x100147518, contains 0x100427d10 - plum, owners 1
11 ark[2041:707] Flush demo2
12 ark[2041:707] End demo2

Which is a bit shorter than before. This is for two reasons:

  • As we are passing a strong variable (instance) to a method (strongIndirect:) which expects a reference to a strong variable there is no need for ARC to use a hidden variable - the variables in line 4 and 5 above are the same (0x100147518).

  • As ARC knows the referenced variable in strongIndirect: is strong there is no need to store an autoreleased reference within strongIndirect: and then write this back after the call - ARC just does a standard strong assignment, lines 6-8, and there is nothing to autorelease later (between lines 11 and 12).

Does strongIndirect: work for strong locals?

Of course, here is demo3:

- (void) demo3
{
   NSLog(@"Strong local passed by strong reference");
   Breadcrumbs *local;                                   // __strong inferred
   local = [Breadcrumbs newWith:@"apple"];
   NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
   [self strongIndirectWrapper:&local];
   NSLog(@"local: addr %p, contains %p - %@, owners %lu", &local, local, local, [local ownerCount]);
}

Executing this with our standard wrapper produces:

1  ark[2041:707] Start demo3
2  ark[2041:707] Strong local passed by strong reference
3  ark[2041:707] >>> 0x100176f30: init
4  ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
5  ark[2041:707] strongIndirect: passed reference 0x7fff5fbfedc0, contains 0x100176f30 - apple, owners 1
6  ark[2041:707] >>> 0x100427d20: init
7  ark[2041:707] >>> 0x100176f30: release
8  ark[2041:707] >>> 0x100176f30: dealloc
9  ark[2041:707] strongIndirect: returned
10 ark[2041:707] local: addr 0x7fff5fbfedc0, contains 0x100427d20 - plum, owners 1
11 ark[2041:707] >>> 0x100427d20: release
12 ark[2041:707] >>> 0x100427d20: dealloc
13 ark[2041:707] Flush demo3
14 ark[2041:707] End demo3

This is almost the same as the previous example, just two minor differences:

  • The address of the local on the stack is passed (0x7fff5fbfedc0), lines 4 and 5

  • As it is stored in a local the new object is cleaned up by ARC, lines 11 and 12

Why not always add __strong to reference arguments?

One reason is because not everything is strong! ARC's pass-by-writeback works for weak locals as well. Our final demo:

- (void) demo4
{
   NSLog(@"Weak local passed by autoreleasing reference");
   instance = [Breadcrumbs newWith:@"peach"];
   Breadcrumbs __weak *weakLocal = instance;
   NSLog(@"weakLocal: addr %p, contains %p - %@, owners %lu", &weakLocal, weakLocal, weakLocal, [weakLocal ownerCount]);
   [self indirectWrapper:&weakLocal];
   NSLog(@"weakLocal: addr %p, contains %p -, %@, owners %lu", &weakLocal, weakLocal, weakLocal, [weakLocal ownerCount]);
}

[Here we've just used instance so we have something to make a weak reference to.]

Executing this with our standard wrapper produces:

 1 ark[2041:707] Start demo4
 2 ark[2041:707] Weak local passed by autoreleasing reference
 3 ark[2041:707] >>> 0x608000000d10: init
 4 ark[2041:707] weakLocal: addr 0x7ffeefbfde58, contains 0x608000000d10 - peach, owners 4
 5 ark[2041:707] >>> 0x608000000d10: retainWeakReference
 6 ark[2041:707] indirect: passed reference 0x7ffeefbfde40, contains 0x608000000d10 - peach, owners 2
 7 ark[2041:707] >>> 0x604000001060: init
 8 ark[2041:707] >>> 0x604000001060: autorelease
 9 ark[2041:707] indirect: returned
10 ark[2041:707] >>> 0x608000000d10: release
11 ark[2041:707] weakLocal: addr 0x7ffeefbfde58, contains 0x604000001060 - banana, owners 4
12 ark[2041:707] Flush demo4
13 ark[2041:707] >>> 0x604000001060: release
14 ark[2041:707] >>> 0x604000001060: dealloc
15 ark[2041:707] End demo4
16 ark[2041:707] >>> 0x608000000d10: release
17 ark[2041:707] >>> 0x608000000d10: dealloc

Notes:

  • Lines 3, 16 & 17 are related to instance - create a new value and release & deallocated at the end - the important stuff starts at line 4

  • Line 4 shows what has been assigned to weakLocal, note that copying the strong reference from `instance into this weak variable does not require any retain. (Note: displaying the contents of a weak variable does involved some retain and release operations, these have been elided for clarity.)

  • ARC uses a hidden variable (line 6, 0x7ffeefbfde40) for weak locals (line 4, 0x7ffeefbfde58) as well. In the strong local case (demo1) ARC knows the reference stored in this hidden variable will remain valid and avoids using the autorelease pool. In this case this isn't guaranteed but ARC still manages to avoid the autorelease pool: ARC retains the reference (line 5, retainWeakReference is a special version of retain for weak variables) and after the call has completed balances this with a release (line 10). This shortens the lifetime of the strong reference compared to using the autorelease pool.

  • The autoreleased assignment (0x604000001060) inside indirectWrapper (line 8) is balanced when the pool is drained (lines 13 & 14). Finally ARC cleans up the object stored in instance (0x608000000d10) when our ByRef instance goes away.

Summary

  • Without any added attributes ARC will do the right thing for local (inferred strong) variables passed as parameters by reference (inferred autoreleasing). (And "local" includes parameters to the current method.)

  • This is implemented by ARC using pass-by-writeback and only works if you follow the "out" parameter pattern. If you wish to store the passed reference for use later you'll need to do more yourself.

  • If you wish to pass instance variables by reference you either need to copy them into locals or attribute the receiving parameter type with __strong.

  • pass-by-writeback also works for __weak locals.


Addendum Apr 2016: __block variables

In the comments Heath Borders has asked:

What if my local variable is a __block type? I'm pretty sure this case is the same as an instance variable in that I need to either copy them to locals, or attribute the receiving parameter type with __strong, but I'm curious about someone else's opinion.

Interesting question.

The specification states:

The pass-by-writeback is ill-formed if the argument expression does not have a legal form:

&var, where var is a scalar variable of automatic storage duration with retainable object pointer type

Local variables in (Objective-)C by default have automatic storage duration - they are automatically created and destroyed as their enclosing function/method/block is entered/exited. In the above answer when we refer to "local variable" we are implicitly referring to local variables with automatic storage duration.

Local variables can be declared with a storage qualifier or storage class specifier to change the storage duration of the variable. The most commonly seen one is static; local variables with static storage duration exist throughout the execution of the program but are only (directly) accessible within their local scope.

If you attempt to pass a static local variable with pass-by-writeback the compiler will produce an error indicating the variable does not have automatic storage duration. You must handle such variables in the same way as instance variables (which have allocated storage duration).

The __block storage qualifier was introduced into (Objective-)C as part of blocks and the specification states:

The __block storage qualifier is mutually exclusive to the existing local storage qualifiers auto, register, and static. Variables qualified by __block act as if they were in allocated storage and this storage is automatically recovered after last use of said variable.

So a __block local variable acts as if it has allocated storage duration, just like instance variables, and so by the specification of pass-by-writeback such a variable cannot be used as it does not have automatic storage duration...

However with the tools current at the time of writing (Xcode 7.2, Clang 7.0.2) __block qualified local variables are supported by pass-by-writeback and are handle the same as those with automatic storage duration - a hidden __autoreleasing temporary is used.

This appears to be undocumented.

Having said that it is "safe" to use in the sense that it will either compile or not, and once compiled the code will work even if the tools change and it cannot be compiled again in the future... (at least without handling the variable the same was as instance variables must be handled).

The reason why it can be accepted can be gleaned from the rationale for the restrictions on pass-by-writeback (emphasis added):

Rationale

The restriction in the form of the argument serves two purposes. First, it makes it impossible to pass the address of an array to the argument, which serves to protect against an otherwise serious risk of mis-inferring an “array” argument as an out-parameter. Second, it makes it much less likely that the user will see confusing aliasing problems due to the implementation, below, where their store to the writeback temporary is not immediately seen in the original argument variable.

There is no technical reason why instance variables could not be supported by pass-by-writeback, but it could be confusing due to aliasing. __block variables lie somewhere between automatic and allocated ones, so maybe the current tool writers choose to group them with the former rather than the latter for pass-by-writeback.

Note: Readers familiar with the implementation of blocks will know that a __block qualified local may be implemented as an optimisation with either automatic or allocated storage duration, depending on usage, and therefore wonder whether this impacts their use for pass-by-writeback. This does not appear to be the case.

starball
  • 20,030
  • 7
  • 43
  • 238
CRD
  • 52,522
  • 5
  • 70
  • 86
  • 9
    What a great answer. That's exactly the kind of insight I was hoping for. Thank you very much! – Steve Jan 12 '12 at 15:36
  • 1
    Wow! This definitely goes down in the SO hall of fame! Thanks for taking the time to write that. Great response. – Chris Maddern Apr 04 '13 at 21:52
  • I was gonna say what Chris said - dang, @CRD you're the man (or woman)! – taber Nov 15 '13 at 09:24
  • 1
    Great answer. Another reason to use `strongIndirect` is if it contains a block that would capture `byRef`. Using the autoreleasing variant can result in crashes (in `objc_retain`) when the caller tries to assign the deallocated temporary back to the strong object pointer. – p00ya Oct 21 '15 at 13:03
  • What if my local variable is a `__block` type? I'm pretty sure this case is the same as an instance variable in that I need to either copy them to locals, or attribute the receiving parameter type with `__strong`, but I'm curious about someone else's opinion. It's probably worth adding it to the summary. – Heath Borders Apr 01 '16 at 06:59
  • @HeathBorders - Interesting question, added an addendum. – CRD Apr 01 '16 at 21:08
  • I created a question about a couple of conflicting behaviors with `__block` variables I saw http://stackoverflow.com/q/36350897/9636 – Heath Borders Apr 02 '16 at 00:04
  • Wonderful writeup, I'd love some refinement regarding why using a `__weak` variable with a `* __strong *` method parameter. Assuming the mismatch will produce code similar to the autoreleasing variant, the only difference is that the indirect's object will be released at the end of the scope (when the `__strong tmp`'s scope ends) instead of at the end of the current autoreleasepool. I can understand why that might be more surprising depending on how you structure your code. But is that the only difference or am I missing something? – Barak Yoresh Nov 28 '19 at 12:05
  • @BarakYoresh - At least with recent compilers (Xcode 10.1/Clang 8.0.0 & Xcode 11.2.1/Clang 11.0.0) passing a `__weak` variable by reference to a `* __strong *` parameter is rejected with the error "Sending `X *__weak *` to parameter of type `X *__strong *` changes retain/release properties of pointer". You could of course do it "manually" using a local strong temp but it probably wouldn't effect the lifetime as you expect as for the weak var to be non-nil at all requires that some var is holding a strong reference. Note: in answering this I updated Demo4 above you might find that helpful. HTH – CRD Nov 28 '19 at 22:39
6

This is perfectly legitimate. The property access is irrelevant; passing a pointer to an object is commonly done with NSError* objects.

The correct way to declare your method is

- (returntype)doSomething:(Foo * __autoreleasing *)arg;

This declares it as a pointer to an __autoreleasing object, which basically means that the object being pointed to is assumed to have been -autoreleased.

As for the "Furthermore", that's not an issue under ARC. Your line

Foo * temp = self.bar;

is equivalent to

__strong Foo *temp = self.bar;

which I hope is obvious to you that this makes temp a strong reference, and thus it "owns" its value for as long as the variable exists. In other words, you can say

Foo *temp = self.bar;
self.bar = nil;

and temp is still valid.

Lily Ballard
  • 182,031
  • 33
  • 381
  • 347
  • For the "furthermore"; does your statement still hold if `temp` is an instance variable? – Steve Jan 11 '12 at 06:47
  • @Steve: My statement holds as long as the variable is `__strong`, which is the default state for variables under ARC. – Lily Ballard Jan 11 '12 at 07:55
  • Thanks for your time. I hate to belabor this, but could you possibly check my edit to confirm my understanding of your answer? – Steve Jan 11 '12 at 16:07
  • I get this error: `passing address of non-local object to __autoreleasing parameter for write-back` – Steve Jan 11 '12 at 16:12
  • @Steve: as you've found your edit is wrong. The way "out" parameters are handled is described in the documentation as "the least bad solution", so some confusion is understandable! Also `__autoreleasing` on a parameter is documented as being inferred, so @Kevin's answer is correct but theoretically redundant... I'll add a proper answer later if nobody beats me to it. – CRD Jan 11 '12 at 18:43
  • @CRD Thanks... Obviously I'm not "stuck" on this - I'm simply passing a (weak) reference to `ObjectA` to `ObjectB` (instead of an out parameter). `ObjectB` simply gets/sets the value straight to the `strong` property on `ObjectA`. My question is really more for my understanding of what's possible/workable and what the pros/cons of the various options are. So I'd definitely appreciate your full answer for what an "out parameter" solution would look like. – Steve Jan 11 '12 at 19:16
  • @Steve: Why are you storing a `Foo * __autoreleazing *` as an ivar? that's not at all what you want to do. In fact, I'm not really sure anymore what you were trying to accomplish with that. – Lily Ballard Jan 11 '12 at 19:49
  • @KevinBallard I want to pass off a reference to a pointer so the other class can change what it's pointing at. There are a whole sequence of asynchronous events (some user driven) which take place before the reference gets updated... so It's not just a single method call per-se. I was just trying to simplify the question. – Steve Jan 11 '12 at 19:54
  • @Steve: Sounds like a confused architecture. Perhaps you should just hand it a completion block that gets called when the asynchronous events are done? – Lily Ballard Jan 11 '12 at 20:11
  • @Steve: In any case, my answer was written for the classic out-parameter style method, where the method synchronously writes a new value to the parameter. That's not what you're doing. If you absolutely need to store a pointer to an object, then you should just drop the `__autoreleasing` bit. But the completion block would be a far better approach. – Lily Ballard Jan 11 '12 at 20:13
  • @KevinBallard, Well I guess I don't understand why it's so hard when it was so easy before (pre-ARC). I understand the alternatives (delegates, completion blocks, references to the instance that has the strong property, etc) and I'm using those alternatives now - but I'm trying to understand how to do something that was simple previously in an ARC context. – Steve Jan 11 '12 at 20:22
  • @Steve: It shouldn't be hard. Did you actually try using a straight `Foo**` before you posted your question? I believe ARC should be able to handle that without a problem. – Lily Ballard Jan 11 '12 at 20:25
  • @KevinBallard I'm trying to understand the ownership roles... and they aren't clear to me. Hows does ARC know that it's updating something that is a strong reference and not a weak one - since anyone could pass a `Foo**` in? – Steve Jan 11 '12 at 20:29
  • @Steve: Given that you're trying to hold onto the `Foo**` as an ivar, I'm not entirely positive how ARC handles the lifecycle. I know that declaring a method with a `Foo**` parameter implicitly declares that as `Foo*__autoreleasing*`, and passing in a strong parameter to that will create an anonymous `__autoreleasing` variable that contains the value you're trying to pass in, a pointer to that variable will be passed to the method, and then when the method returns the value of that anonymous variable will be stuffed back into your original strong var. – Lily Ballard Jan 11 '12 at 20:41
  • @Steve: However, this behavior assumes the standard out-param conventions, which is that the method you're passing the pointer to doesn't hold onto the pointer past the stack frame. So in your case I'm not really sure what will happen. But I do know that what you're doing right now is a poor architecture anyway, and it's probably a good thing that ARC is forcing you to revisit your assumptions about object lifecycle. There's a lot of stuff you can get away with in MRR that just doesn't fly under the stricter rules of ARC. – Lily Ballard Jan 11 '12 at 20:43
  • @KevinBallard, Again (#3) I'm NOT doing this now... I'm simply trying to understand how the ownership roles work in ARC in a situation such as this. – Steve Jan 11 '12 at 21:11