mikeash.com: just this guy, you know?

Posted at 2011-09-30 15:02 | RSS feed (Full text feed) | Blog Index
Next article: Friday Q&A 2011-10-14: What's New in GCD
Previous article: Friday Q&A 2011-09-16: Let's Build Reference Counting
Tags: arc cocoa fridayqna memory objectivec
Friday Q&A 2011-09-30: Automatic Reference Counting
by Mike Ash  
This article is also available in Hungarian (translation by Szabolcs Csintalan).

Since the moment Apple announced it, readers have asked me to write about Automatic Reference Counting, or ARC. Today is the day. I'll talk about Apple's new memory management system, how it works, and how to get the most out of it.

Conceptual
The Clang static analyzer is a really useful tool for finding memory management errors in code. If you're like me, you've looked at the output of the analyzer and thought, "If you can spot the error, why can't you just fix it for me too?"

That, in essence, is what ARC is. The memory management rules are baked into the compiler, but instead of using them to help the programmer find mistakes, it simply inserts the necessary calls on its own.

ARC occupies a middle ground between garbage collection and manual memory management. Like garbage collection, ARC frees the programmer from writing retain/release/autorelease calls. Unlike garbage collection, however, ARC does not deal with retain cycles. Two objects with strong references to each other will never be collected under ARC, even if nothing else refers to them. Because of this, while ARC frees the programmer from dealing with most memory management issues, the programmer still has to avoid or manually break cycles of strong references in the object graph.

When it comes to implementation specifics, there's another key difference between ARC and Apple's implementation of garbage collection: ARC is not an either/or proposition. With Apple's garbage collector, either the entire application runs under GC, or none of it does. This means that all Objective-C code in an application, including all of Apple's frameworks and all third-party libraries you might include, must be GC compatible for you to take advantage of GC. In contrast, ARC coexists peacefully with non-ARC manual memory managed code in the same application. This makes it possible to convert projects piecemeal without the massive compatibility and reliability problems that garbage collection ran into when it was first introduced.

Xcode
ARC is available in Xcode 4.2, currently in beta, and only when compiling with Clang (a.k.a. "Apple LLVM compiler"). The setting is called, obviously enough, "Objective-C Automatic Reference Counting". Turn it on, and off you go.

If you're working on existing code, changing this setting will produce an enormous quantity of errors. ARC not only manages memory for you, but it forbids you from trying to do it yourself. It's illegal to manually send retain/release/autorelease when using ARC. Since normal non-ARC Cocoa code is littered with this stuff, you'll get a lot of errors.

Fortunately, Xcode offers a tool to convert existing code. Select Edit -> Refactor... -> Convert to Objective-C ARC... and Xcode will guide you through converting your code. Although there may be some situations where it needs help figuring out what to do, the process should be largely automatic.

Basic Functionality
Cocoa memory management rules are fairly simple. In short:

  1. If you alloc, new, copy, or retain an object, you must balance that with release or autorelease.
  2. If you obtain an object from something other than the above, and you need it to stay alive long-term, you must retain or copy it. This must, of course, be balanced later.

These are highly suitable for automation. If you write this:

    Foo *foo = [[Foo alloc] init];
    [foo something];
    return;

The compiler can see the unbalanced alloc. The code is thus transformed:

    Foo *foo = [[Foo alloc] init];
    [foo something];
    [foo release];
    return;

In reality, the compiler does not insert a message send to release. Instead, it inserts a call to a special runtime function:

    Foo *foo = [[Foo alloc] init];
    [foo something];
    objc_release(foo);
    return;

This allows for some optimization. In the common case where -release is not overridden, the objc_release function can bypass Objective-C messaging, resulting in a bit of a speed gain.

This automation can make code safer. Most Cocoa programmers interpret "long-term" in rule #2 to mean objects stored in instance variables and similar places. We don't normally retain and release local temporary objects:

    Foo *foo = [self foo];
    [foo bar];
    [foo baz];
    [foo quux];

However, this can be dangerous:

    Foo *foo = [self foo];
    [foo bar];
    [foo baz];
    [self setFoo: newFoo];
    [foo quux]; // crash

The standard way to work around this is to have the -foo getter do a retain/autorelease before returning the value. This works, but can build up a lot of temporary objects leading to excessive memory usage. ARC, however, will be paranoid and insert extra calls here:

    Foo *foo = objc_retainAutoreleasedReturnValue([self foo]);
    [foo bar];
    [foo baz];
    [self setFoo: newFoo];
    [foo quux]; // fine
    objc_release(foo);

Likewise, even if you write a plain getter, ARC will make it safe as well:

    - (Foo *)foo
    {
        return objc_retainAutoreleaseReturnValue(_foo);
    }

But wait, this doesn't solve the problem of excessive temporary objects at all! We're still doing a retain/autorelease sequence in the getter, and a retain/release combination in the calling code. This is considerably less efficient!

Not to worry. As I mentioned above, ARC emits these special calls instead of plain message sends for the purposes of optimization. In addition to simply making retain and release faster, these calls are able to eliminate certain operations altogether.

When objc_retainAutoreleaseReturnValue runs, it looks on the stack and grabs the return address from its caller. This allows it to see exactly what will happen after it finishes. When compiler optimizations are turned on, the call to objc_retainAutoreleaseReturnValue will be subject to tail-call optimization, and the return address will point to the call to objc_retainAutoreleasedReturnValue.

With this crazy return-address examination, the runtime is able to see that it's about to perform some redundant work. It therefore eliminates the autorelease, and sets a flag that tells the caller to eliminate its retain. The whole sequence ends up doing a single retain in the getter and a single release in the calling code, which is both completely safe and efficient.

Note that this optimization is fully compatible with non-ARC code. In the event that the getter doesn't use ARC, the flag won't be set and the caller will perform a full retain/release combination. In the event that the getter uses ARC but the caller does not, the getter will see that it's not returning to code that immediately calls the special runtime function, and will perform a full retain/autorelease combination. Some efficiency is lost, but correctness is preserved.

In addition to all of this, ARC also automatically creates or fills out a -dealloc method for all classes to release their instance variables. It's still possible to manually implement -dealloc, and it's necessary for classes which manage external resources, but it's no longer necessary (or possible) to manually release instance variables. ARC will even put the [super dealloc] at the end for you, so you don't have to. Previously, you might have written this:

    - (void)dealloc
    {
        [ivar1 release];
        [ivar2 release];
        free(buffer);

        [super dealloc];
    }

Now you can just write this:

    - (void)dealloc
    {
        free(buffer);
    }

In the event that your -dealloc method just releases instance variables, it can simply be eliminated altogether.

Cycles and Weak References
ARC still requires the programmer to manually resolve reference cycles, and the best way to resolve reference cycles is typically to use weak references.

ARC provides zeroing weak references. These are weak references which not only don't keep the referenced object alive, but which also automatically become nil when the referenced object is destroyed. Zeroing weak references avoid the potential for dangling pointers and the associated crashes and mysterious behavior.

To make a zeroing weak variable, simply prefix its declaration with __weak. For example, here is a weak instance variable:

    @interface Foo : NSObject
    {
        __weak Bar *_weakBar;
    }

Likewise for local variables:

    __weak Foo *_weakFoo = [object foo];

You can then use it like any other variable, with the value automatically becoming nil when appropriate:

    [_weakBar doSomethingIfStillAlive];

Note, however, that a __weak variable can become nil at almost any time. Memory management is an inherently multithreaded activity, and a weakly referenced object could be destroyed on one thread while another thread is accessing it. Code like this is therefore not valid:

    if(_weakBar)
        [self mustNotBeNil: _weakBar];

Instead, store the object into a local strong reference and test that:

    Bar *bar = _weakBar;
    if(bar)
        [self mustNotBeNil: bar];

Because bar is a strong reference here, the object is guaranteed to stay alive (and the variable non-nil) throughout this code.

ARC's implementation of zeroing weak references requires close coordination between the Objective-C reference counting system and the zeroing weak reference system. This means that any class which overrides retain and release can't be the target of a zeroing weak reference. While this is uncommon, some Cocoa classes, like NSWindow, suffer from this limitation. Fortunately, if you hit one of these cases, you will know it immediately, as your program will crash with a message like this:

    objc[2478]: cannot form weak reference to instance (0x10360f000) of class NSWindow

If you really must make a weak reference to classes such as these, you can use the __unsafe_unretained qualifier in place of __weak. This creates a weak reference which is not zeroing. You must ensure that you never use such a pointer (preferably by zeroing it out manually) after the object it points to has been destroyed. Be careful, as non-zeroing weak references are playing with fire.

While it's possible to build programs using ARC that run on Mac OS X 10.6 and iOS 4, zeroing weak references are not available on those OSes. All weak references must be __unsafe_unretained here. Because non-zeroing weak references are so dangerous, this limitation significantly decreases the attractiveness of ARC on those OSes in my view.

Properties
Since properties are so tightly coupled to memory management, it makes sense that ARC would introduce some new behaviors there.

ARC introduces a few new ownership modifiers. Declaring a property as strong makes that property a strong reference. Declaring it as weak uses a zeroing weak reference. The unsafe_unretained modifier uses a non-zeroing weak reference. When @synthesize is used, the compiler creates an instance variable of the same storage type.

The existing modifiers of assign, copy, and retain still exist and work the same way they did before. Notably, assign creates a non-zeroing weak reference, so it should be avoided whenever possible.

Aside from the new modifiers, properties work just as they always have.

Blocks
Blocks are Objective-C objects, and as such are also managed by ARC. Blocks have special memory management requirements, and ARC treats them accordingly. Block literals must be copied, not retained, which in practice means that it's best to copy rather than retain blocks everywhere. ARC follows this practice.

Additionally, ARC knows that block literals must be copied if they're used after the current scope returns. Non-ARC code needs to explicitly copy and autorelease returned blocks:

    return [[^{
        DoSomethingMagical();
    } copy] autorelease];

With ARC, this simply becomes:

    return ^{ DoSomethingMagical(); };

However, beware! ARC currently does not automatically copy a block literal that's converted to an id. So while this code is fine:

    dispatch_block_t function(void)
    {
        return ^{ DoSomethingMagical(); };
    }

This code is not:

    id function(void)
    {
        return ^{ DoSomethingMagical(); };
    }

It's easy to work around by simply copying the block, but it's something to be careful with:

    return [^{ DoSomethingMagical(); } copy];

Likewise, you need to explicitly copy blocks that you pass as id parameters:

    [myArray addObject: [^{ DoSomethingMagical(); } copy]];

Fortunately, it appears that this is just an edge case that fell through the cracks and is likely to be fixed soon. There's no problem with throwing in an extra manual copy if you're unsure.

Another significant change with ARC is the behavior of __block qualified variables. The __block qualifier allows a block to modify a captured variable:

    id x;
    __block id y;
    void (^block)(void) = ^{
        x = [NSString string]; // error
        y = [NSString string]; // works
    };

Without ARC, __block also has the side effect of not retaining its contents when it's captured by a block. Blocks will automatically retain and release any object pointers they capture, but __block pointers are special-cased and act as a weak pointer. It's become a common pattern to rely on this behavior by using __block to avoid retain cycles.

Under ARC, __block now retains its contents just like other captured object pointers. Code that uses __block to avoid retain cycles won't work anymore. Instead, use __weak as described above.

Toll-Free Bridging
ARC only works on Objective-C types. CoreFoundation types still have to be managed manually by the programmer. Because there is ambiguity about ownership, ARC forbids standard casts between pointers to Objective-C objects and pointers of other types, including pointers to CoreFoundation objects. The following code, which is fairly typical under manual memory management, does not compile with ARC:

    id obj = (id)CFDictionaryGetValue(cfDict, key);

In order to make this compile again, you must tell ARC about the ownership semantics involved by using special casting annotations. These annotations are __bridge, __bridge_retained, and __bridge_transfer.

The simplest one to understand is __bridge. This is a direct conversion with no ownership consequences. ARC receives the value and then manages it normally. This is what we want for the above:

    id obj = (__bridge id)CFDictionaryGetValue(cfDict, key);

The other casting annotations transfer ownership to and from the ARC system. These can help ease the pain when bridging back and forth.

Here's an example of using bridging in a situation where the returned object needs to be released.

    NSString *value = (NSString *)CFPreferencesCopyAppValue(CFSTR("someKey"), CFSTR("com.company.someapp"));
    [self useValue: value];
    [value release];

If we move this to ARC by using __bridge, removing the release, and otherwise not making any changes, we end up with a leak:

    NSString *value = (__bridge NSString *)CFPreferencesCopyAppValue(CFSTR("someKey"), CFSTR("com.company.someapp"));
    [self useValue: value];

The Copy in this code needs to be balanced with a release. ARC will emit a retain when initializing value, then balance that with a release when value is no longer used. Since nothing balances the original Copy, that object is leaked.

We can work around this with a little extra code:

    CFStringRef valueCF = CFPreferencesCopyAppValue(CFSTR("someKey"), CFSTR("com.company.someapp"));
    NSString *value = (__bridge NSString *)valueCF;
    CFRelease(valueCF);

    [self useValue: value];

This is getting fairly verbose, though. Since the whole point of toll-free bridging is to be as painless as possible, and the whole point of ARC is to remove the need to write memory management code, it would be nice if this could be made more straightforward.

The __bridge_transfer annotation solves this problem. Rather than simply move a pointer value into ARC, it moves the value and transfers ownership. When __bridge_transfer is used in a cast, it tells ARC that this object is already retained, and that ARC doesn't need to retain it again. Since ARC takes ownership, it will still release it when it's done. The net result is that everything works the way it's supposed to:

    NSString *value = (__bridge_transfer NSString *)CFPreferencesCopyAppValue(CFSTR("someKey"), CFSTR("com.company.someapp"));
    [self useValue: value];

Toll-free bridging works both ways. As before, ARC doesn't allow a standard cast to convert from an Objective-C object pointer to a CoreFoundation object pointer. This code won't compile under ARC:

    CFStringRef value = (CFStringRef)[self someString];
    UseCFStringValue(value);

Adding a __bridge to the cast makes it compile, but the resulting code is dangerous:

    CFStringRef value = (__bridge CFStringRef)[self someString];
    UseCFStringValue(value);

Since ARC doesn't manage the lifetime of value, it will release ownership of the object immediately, before it gets passed to UseCFStringValue, potentially causing a crash or other misbehavior. By using __bridge_retained, we can tell ARC to transfer ownership out of the system and into our hands. Since ownership is transferred, we're now responsible for releasing the object when done with it, just like with any other CF code:

    CFStringRef value = (__bridge_retained CFStringRef)[self someString];
    UseCFStringValue(value);
    CFRelease(value);

These cast annotations are useful outside of toll-free bridging as well. Any time you need to store an object pointer in storage that's not managed as an Objective-C object, they smooth the way. There are void * context pointers found in various places in Cocoa, and a prominent example is sheets. Without ARC:

    NSDictionary *contextDict = [NSDictionary dictionary...];
    [NSApp beginSheet: sheetWindow
       modalForWindow: mainWindow
        modalDelegate: self
       didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
          contextInfo: [contextDict retain]];


    - (void)sheetDidEnd: (NSWindow *)sheet returnCode: (NSInteger)code contextInfo: (void *)contextInfo
    {
        NSDictionary *contextDict = [(id)contextInfo autorelease];
        if(code == NSRunStoppedResponse)
            ...
    }

As before, this fails under ARC, because normal casts between object and non-object pointers are not allowed. However, using the cast modifiers, we can not only get ARC to allow it, but also get ARC to do the requisite memory management for us:

    NSDictionary *contextDict = [NSDictionary dictionary...];
    [NSApp beginSheet: sheetWindow
       modalForWindow: mainWindow
        modalDelegate: self
       didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:)
          contextInfo: (__bridge_retained void *)contextDict];


    - (void)sheetDidEnd: (NSWindow *)sheet returnCode: (NSInteger)code contextInfo: (void *)contextInfo
    {
        NSDictionary *contextDict = (__bridge_transfer NSDictionary *)contextInfo;
        if(code == NSRunStoppedResponse)
            ...
    }

To summarize:

Structs
Under ARC, structs and Objective-C object pointers pretty much don't mix. The problem is that there is no good way for the compiler to know when a particular struct is destroyed or copied, and thus no good place for the compiler to insert the necessary retain and release calls. Because it's such a difficult problem, and because putting object pointers in structs is so unusual anyway, ARC just gives up on the whole proposition. If you want to put an Objective-C object pointer in a struct, you must qualify it with __unsafe_unretained, and deal with all of the problems and danger that this implies.

Because it's so uncommon to put Objective-C pointers into structs, it's likely that this won't be a problem for your code. If it is, your best bet is to change the struct into a lightweight Objective-C class instead. ARC will start managing memory for you and the problem goes away.

Further Reading
While Apple's official documentation on ARC is still under wraps while Xcode 4.2 is in beta, a great deal of information about the system is available on the Clang site here: http://clang.llvm.org/docs/AutomaticReferenceCounting.html

Conclusion
Automatic reference counting substantially reduces the burden on the programmer for dealing with memory management. ARC is not a full garbage collector. It cannot detect retain cycles, and these must be dealt with and broken by the programmer. It still takes a lot of the grunt work out of writing Cocoa code, and the zeroing weak references that it provides are a powerful tool for dealing with cycles.

Things get trickier when it comes to CoreFoundation objects and toll-free bridging. ARC limits itself to dealing with Objective-C, so the programmer still needs to manage the CoreFoundation side manually. When converting between Objective-C and CoreFoundation pointers, the special __bridge cast modifiers need to be used to inform ARC about the memory management semantics of the conversion.

That wraps up today's exploration of Apple's latest programming language technology. Come back in two weeks for another fine word salad. Until then, keep watching the skies and sending in your suggestions for topics.

Did you enjoy this article? I'm selling whole books full of them! Volumes II and III are now out! They're available as ePub, PDF, print, and on iBooks and Kindle. Click here for more information.

Comments:

Other than the automatic breaking of retain cycles, do you believe that any practical reason exists to use garbage collection instead of ARC? Up until ARC's announcement, GC was still being evangelized by some Apple developers on the Cocoa mailing list and sites like StackOverflow, making ARC's announcement slightly surprising.
What about the previous retain/copy properties, how would one specify that you want a copy setter/getter synthesized with a strong property?

Also, how would you override weak/strong synthesized properties with ARC?
What's the correct way to declare simple (number) properties with ARC?
I used to write @property(assign) BOOL flag; but now it sounds like assign should be avoided. But "unsafe-unretained' doesn't sound like it would be problematic with, say, an NSInteger ivar. Do I understand this correctly?
Preston: The only thing that separates ARC from being a true garbage collector is being able to handle retain cycles. Automatic refcounting plus a cycle collector is a pretty common way to do garbage collection, actually. IIRC both Python and PHP work this way, for example. However, I think that the benefit of automatic cycle management shouldn't be understated. Cycles can happen in places where you wouldn't expect, so there's definitely value in having them broken for you.

However, the language around ARC makes it sound like Apple is planning to phase out GC in favor of ARC, so even though GC has advantages, these are probably outweighed by the fact that ARC code will have better longevity and portability.

Marc: Copy properties are fine, and are implicitly strong. Retain properties are also strong, but it's preferred that you explicitly use strong instead. For overriding, all you need to do is make sure that the backing storage has the correct semantics. If you write your own accessors for a strong property, a normal ivar will do. For a weak property, a __weak ivar will do it.

Iain: ARC only affects object pointers, so for primitives you can simply carry on as usual.
You should probably be using these functions instead of the casting modifiers:

CFBridgingRetain()
CFBridgingRelease()
Thanks Mike. This is much clearer than the Apple docs. The examples are very helpful.
Nice article!

In the places where you meant objc_autoreleaseReturnValue you wrote objc_retainAutoreleaseReturnValue.

Also, Dave++. If you use CFBridgingRetain and CFBridgingRelease, then the CF ref count looks balanced. For example,

NSString *str = CFBridgingRelease(CFStringCreate(...));

I find the semantics much easier to keep track of, and it's efficient. CFBridgingRelease is basically transfer one ref count from CF to objc, and the stack's strong, so in effect that is "don't generate any code, but make stuff look balanced".
Dave: Alas, those are not publicly documented yet. I've actually found the casting modifiers growing on me while working on this stuff.

ken: I'm pretty sure I want objc_retainAutoreleaseReturnValue, since an ivar accessor needs to do a retain/autorelease combo.

Regarding the efficiency of the bridging functions, I thought they were just doing the same thing as the casts, so they should be the same, efficiency-wise.
If you are exposing a Block property, you should always declare the property as copy, not strong. The current compiler has a bug where a Block property that is declared strong is retained instead of copied, which can lead to crashing issues.
Very nice write-up, thanks very much, Mike!

So, what's your take on ARC: a good thing, a meh thing, 'good riddance GC', none of the above?... :-)
My take on ARC has two facets.

Taken entirely on its own, ARC is great. It gets rid of a ton of grunt work at a minimum of overhead and complexity. It's a perfect case where the compiler can step in and take a bunch of boring stuff away from the programmer.

Taken in the larger context, where all of this work on ARC fairly heavily implies that Apple has given up on garbage collection, I'm sad. The ObjC GC has a lot of problems, but I was hopeful that it could be made better with time.
If you would use the "Leaks" tool with ARC it will show you the cycle references.

Also, in the nice graphical way:
http://dl.dropbox.com/u/27714647/screen.png

You can read about it (and other things about ARC) in the presentation here
http://dl.dropbox.com/u/27714647/ITJam2011%20ARC.key
This one is correct:

    Foo *foo = objc_retainAutoreleasedReturnValue([self foo]);


this one should be objc_autoreleaseReturnValue.


    - (Foo *)foo
    {
        return objc_retainAutoreleaseReturnValue(_foo);
    }


They have to be paired.

According to the Clang document I linked above, objc_autoreleaseReturnValue just autoreleases the value passed to it, as you would expect. This is incorrect to do to an ivar returned from a basic accessor, and will lead to an over-release and likely subsequent crash.

objc_retainAutoreleaseReturnValue does a retain and an autorelease, which is precisely what is needed here.

objc_retainAutoreleasedReturnValue can be paired with either of the above. Which one of the above is needed depends entirely on the semantics of the called method. If the called method allocs (or retains or copies) something and then needs to return it to the caller, it will use objc_autoreleaseReturnValue. If the called method is returning a value which it has not alloced (or retained or copied), like an ivar, then it will use objc_retainAutoreleaseReturnValue to do the retain/autorelease combination necessary for that case.
What I said can easily be verified by simply compiling some code and looking at the disassembly:

-[TestClass foo]:
0000000100000dd0    pushq    %rbp
0000000100000dd1    movq    %rsp,%rbp
0000000100000dd4    movq    0x0000040d(%rip),%rax
0000000100000ddb    movq    (%rdi,%rax),%rdi
0000000100000ddf    popq    %rbp
0000000100000de0    jmp    0x100000e7a    ; symbol stub for: _objc_retainAutoreleaseReturnValue
0000000100000de5    nopl    %cs:0x00000000(%rax,%rax)


Yay, I finally understand __bridge*! Thanks! Good block memory management summary too, I lazilly linked to it instead of writing about it myself from my blocks guide...

I'm rather sad that the GC seems to be dying, I wonder if that means macruby's future suddenly turned dark :( Would so love to use that on iOS...
Thanks so much for this explanation of toll-free bridging with ARC! I've been combing message boards, documentation, and headers for any sort of clue as to how this is supposed to work, and you elegant examples are the first to make sense to me.
How will ARC's weak references affect your MAZeroingWeakRef project? Will code using MAZeroingWeakRef convert to ARC without problems or should it be stripped in favor of the new __weak prefix?
nevyn: I wonder how practical it would be for third parties to add a cycle detector on top of ARC to turn it into a real GC. Performance would probably not be the best, but it may not be completely ridiculous....

Grzegorz Adam Hankiewicz: MAZeroingWeakRef can be used fine in ARC projects as long as those particular files are compiled as non-ARC. MAZWR is useful if you're using ARC but targeting 10.6/iOS4 where official ZWRs aren't available. If you're targeting 10.7/iOS5, then MAZWR doesn't offer any real advantage over the built-in stuff, and in fact it will use the built-in stuff when available.

(The one potential advantage of MAZWR is that it can work with classes like NSWindow which don't work with the ARC version. Right now it doesn't, but in theory it could fall back to the dynamic subclass craziness for those classes. I'm not sure if this is worthwhile to build.)
Nice article, very well explained.

I think I have some unlearning to do though, since this sentence:

There's no problem with throwing in an extra manual copy if you're unsure.

made my spine crawl just a little bit :-p

scott
Scott Little: Understandable. However, consider: once a block has been copied to the heap, further copies do nothing but increment the reference count, so they are essentially free. ARC will automatically balance those not-copies with releases. So, while it sounds bad, there really is no harm in doing a [block copy] where it's not necessary, when using ARC.
The following statement confuses me a bit:



    Bar *bar = _weakBar;
    if(bar)
        [self mustNotBeNil: bar];

Because bar is a strong reference here, the object is guaranteed to stay alive (and the variable non-nil) throughout this code.


What exactly do you mean with "the object is guaranteed to stay alive"? I understand that bar will never he zero'ed by ARC, but why can't the referenced object be released in another thread? It's a simple assignement operation, what exactly makes it a strong reference?
mkseiser: It's because object pointers are implicitly __strong. So, another way to write that would have been:


__strong Bar *bar = _weakBar;
if(bar)
    [self mustNotBeNil: bar];
mkeiser: Oh, I see your question. Sure, another part of your program that isn't using ARC could erroneously release that object. But that'd be really dumb, and would probably be picked up by the static analyzer anyway. But within the context of ARC, the object will indeed stay alive.
This article is great! One other item is to note how ARC is very particular about naming conventions, and that it will do the *wrong* thing if you break those conventions. For example: [foo newsFeedWithObject:bar] will make ARC think you are returning a retained object since it has the 'new' prefix.
Jason:

According to the WWDC presentation, ARC is aware of camel case and will know that -newsFeedWithObject: is not a method returning ownership. I don't have iOS developer status and so can't test this in the current 4.2 beta, however.
Note that the naming conventions are important, but only when mixing ARC and non-ARC code. If ARC-using code calls ARC-using code, it doesn't matter what your method is named, because both sides will follow the same convention, even if it's the "wrong" one. However, when ARC calls non-ARC, or the reverse, then you definitely need to get that right.
Once again, a nice read.

One question, though:

How would one silence the warning on -[NSObject performSelector:withObject:] without resorting to objc_msgSend()?
What warnings are you referring to?
@Daniel When LLVM issues a warning, it typically also states the command line switch you can use to disable the warning. You can then use a pragma to turn off that warning like so:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "<warning you want to disable>"
// Code that issues the warning
#pragma clang diagnostic pop

Keep in mind that this is not something you should do to generally kill warnings. Warnings are absolutely there for a reason, and you should take great care before you disable one.

In general, it is likely a good idea to move away from using -performSelector* calls to arbitrary selectors if possible – using blocks or trying to switch to a set of known selectors is generally preferable. Yes, this means that you may want to rethink your target-action pattern based code. At the same time, it is sometimes the correct pattern so don't be afraid to use it if you really think it is correct.
Is there a way for debugging purposes to put a breakpoint where a giving weak reference is zeroed? Of should one rely on a watchpoint?
Sorry for the extreme brevity in my previous question:
I was posting from the phone — which actually ate my more verbose first draft :-(

@Mike When using performSelector* with a non-constant selector under ARC, you get a compiler warning that this may cause a leak — the exact warning Xcode gives you is:
warning: performSelector may cause a leak because its selector is unknown [-Warc-performSelector-leaks,3]
         (void)[target performSelector:selector withObject:self];
                       ^
FILENAME:LINE:COLUMN: note: used here [3]
         (void)[target performSelector:selector withObject:self];
                                       ^
1 warning generated.
.
(Which I now see how to get rid of, for the general case...)

My particular case was a category on NSTimer — one that holds a weak reference to the actual timer-target through indirection.
So the #pragma solution @David mentioned would definitely be an option — although much uglier than resorting to plain old objc_msgSend().

I hoped using one of the CLANG macros like NS_RETURNS_NOT_RETAINED might be an option, but they seem to only be available on method declaration and not inline, at the calling site.
Therefore, I tried defining and explicitly using the following protocol:

@protocol WeakTimerTarget <NSObject>
- (id)performSelector:(SEL)selector withObject:(id)object NS_RETURNS_NOT_RETAINED;
@end

But that didn't do the trick, either.
It’s my understanding that __unsafe_unretained is effectively the same behaviour as “assign” for object pointers (e.g. delegates). If that is actually so, you still need to exercise caution, but it’s perhaps caution that you’re used to exercising for delegates or for breaking retain cycles.

Mike, is that your understanding as well?
You're correct that __unsafe_unretained is the same as a regular assignment done the old way, but most Cocoa programmers don't exercise the caution they should when using those. How much code have you seen that manually zeroes out delegate and data source pointers in a window controller's -dealloc. It's almost unheard of. And yet, it's absolutely required for correctness, because you can't know the order of object destruction, and the view might message its data source or delegate after the controller has been destroyed. In practice, this happens rarely, but it does happen, and is really annoying to track down.

So yes, you should use the same amount of caution as dealing with both. However, that is most likely not the amount of caution that you're used to.
This is iOS 5 only, right?
I have a question about zeroing weak references.

As you noticed earlier zeroing weak references won't work under iOS 4 and I must use __unsafe_unretained when declaring delegates, right?

Thus this will make working with delegates in before-ARC style? Just without automatic zeroing of weak reference?
Sorry, Mike. I have read last comments and got all the answers!
Thanks for clarifying that, Mike. You’re right that I almost never see that done correctly.
I was trying to change some code (a framework) from using garbage collection to arc as I had some bugs with garbage collection (I couldn't force a specific order that objects are destroyed) and thought the more deterministic nature of ARC would benefit more....

However, I keep getting this error: "-fobjc-arc is not supported with fragile abi" on my project. What are the potential causes for this error? My framework uses Oracle's instant client c++ libraries so is objective-c++ as well as 32 bit only as the 64 bit instant client doesn't work on Lion yet. Does arc require 64 bit?
bill: You can target iOS 4 and Mac OS X 10.6 with ARC, but you can't use zeroing weak references there. Those require iOS5/10.7.

Ray: Yes, I believe ARC requires 64-bit, so you're probably out of luck. Note that the order of object destruction is something you should try to avoid relying upon anyway. Order is not guaranteed with ARC either, unless one of the objects has a strong reference to the other.
A minor correction: ARC requires the "new runtime", which means Mac 64-bit or iOS (including simulator). Mac 32-bit is the only "old runtime" platform.
I've been wondering about iOS 4 compatibility. If you can't use weak zeroing references, what pattern should you follow if you want to use ARC on both iOS 4 and 5?
My preferred route would be to use MAZeroingWeakRef wherever possible in that case.

If you don't want the awful hackiness of that approach, you'll basically need to code like you would without ARC when it comes to weak references. Use __unsafe_unretained and be really paranoid about manually zeroing out weak references and not messaging stale pointers.
I've got a garbage-collected project that I'm converting to ARC. Despite garbage collection being set to unsupported and ARC enabled, I'm getting analysis errors as if the project is still garbage collected. Likewise, automatic conversion to ARC does not work because Xcode thinks that my project is still garbage collected. Is this my fault or a bug in Xcode?
Never mind -- I had set garbage collection to unsupported in projects, but not targets.
Any thoughts on converting a GC app to ARC?

(I'm also sad that Apple seems to be ditching GC. Coding in GC one has less to worry about, though no doubt runtime performance will be somewhat better under ARC.)

As changing the fundamental memory management model of a large codebase is not be be done lightly, I'm initially only interested in making ARC-friendly changes that are still valid in the GC case.

Of the top of my head, my (rare) NSAllocateCollectable usage can change to malloc/free, and still work in both cases.

Do the new strong/weak keywords work in GC?

What does NSMakeCollectable do under ARC? What does CFBridgingRelease do under GC?
I think the main troubles will be cycles and CF bridging. I think you can track down cycles with Instruments.

Replacing NSAllocateCollectable will work as long as you remember to implement both dealloc and finalize to free the stuff, in cases where it's tied to the lifetime of an object.

I believe weak properties already worked under GC before ARC. The __weak qualifier definitely works. I'm not sure if strong works, but if not, retain is equivalent.

NSMakCollectable should work under ARC the same as it does under non-ARC non-GC, which is to say that it doesn't do anything. CFBridgingRelease is an inline function so you can see how it works. Under non-ARC it just does a standard CFMakeCollectable/autorelease combination.
Thank you for the great explanation!
Code that uses __block to avoid retain cycles won't work anymore. Instead, use __weak as described above.


What if I need to avoid retain cycles and allow the block to change a variable – with ARC?

Is the __weak qualifier enough or is it necessary to use __block __weak?

I am trying to update my cancellable NSBlockOperation which looked like this without ARC:

__block NSBlockOperation *b = [NSBlockOperation blockOperationWithBlock:^{
    ...
    If (! [b isCancelled]) ...
}];
As far as I know, __weak variables are still immutable when captured. For your example, I'd suggest passing the operation as a parameter to the block so it doesn't have to rely on outside variables. Another option would be to capture a proxy object to the operation rather than capturing it directly.
Generational garbage collections also do heap compaction, which I can't see how ARC could do.
ARC is definitely not able to do heap compaction. However, heap compaction is an implementation detail (albeit a really useful one) of GCs, not a directly outwardly visible feature.
Take a look in this code.

1 __strong NSDictionary* myObject = [[NSDictionary alloc] initWithObjectsAndKeys:@"hello 1", @"message", nil];
2 __weak NSDictionary* weakMyObject = myObject;
3
4 NSLog(@"Message before: %@", [weakMyObject objectForKey:@"message"]);
5
6 myObject = [[NSDictionary alloc] initWithObjectsAndKeys:@"hello 2", @"message", nil];
7
8 NSLog(@"Message after: %@", [weakMyObject objectForKey:@"message"]);

In line 6 myObject points to a new NSDictionary, so I suppose that weakMyObject have to be nil in line 8 but it isn't. What is wrong in my head? When weakMyObject became null.


another question: there is a way yo see the generated ARC's code?
There's no guarantee that the original dictionary in myObject becomes nil on line 6. It may have been autoreleased somewhere, for example, and will remain live until the autorelease pool is popped.

The best way to see the generated code is to disassemble your binary. All of the inserted calls to objc_retain and friends will be there.
ok, why are you talking about autorelease pool?
have you idea when and where the weakMyObject became nil?

Before a test, I've supposed that in line 8 weakMyObject must be nil!
At last, great explanations of ARC. Thanks! Much appreciated.
Great article as always Mike!

One thing I note, which you haven't mentioned and I was astonished about is how amazingly well ARC works with C++ objects. No, ARC wont manage your C++ objects, but you can use Objective C object pointers in your C++ objects (or structs, although that turns them into objects) and ARC will manage them so that they are released when the object is destructed.

I know you're not font of C++, but this is actually quite amazingly well done, and certainly worth a note near where you talk about C structs.

See http://tinyurl.com/Objective-C-ARC for some details - I've verified it all works as expected.

(The link is http://www.informit.com/articles/article.aspx?p=1745876&;seqNum=3 but I couldn't get the comment system to encode the link correctly after the ampersand)
Figured I'd let you in on something I'd discovered that I hadn't seen mentioned. It's related to this error:

    objc[2478]: cannot form weak reference to instance (0x10360f000) of class MyClass

It seems like any time you try to form a weak reference to an object after you reach the object's destructor, you can trigger this error. No override of retain or release needed, as your FAQ stated.

Explanation:

I have some code that stores weak references as the keys to a mutable dictionary (Think NSMapTable, but pre-iOS 6 so NSMapTable isn't available). When my objects are no longer needed in the dictionary, I want to remove the keys and their associated objects.

I added some cleanup code to -dealloc and discovered something: My cleanup code tries to recreate the wrapped object to remove it from the dictionary, but it blows up with the same error above.

I can fix it if I switch to __unsafe_unretained references, but unsafe pointers drive me crazy. I could also let the references go to zero and then clean them up later by looking for zeros, but this seemed less tidy. I've since solved it but figured somebody else might run into this problem.

In case it's not clear, this is a simplified version of what I've got for my wrapper object:

    @interface WeakValue : NSObject
    @property (weak, nonatomic) id nonretainedObject;
    @end
    
    @implementation WeakValue
    @synthesize nonretainedObject;
    - (BOOL)isEqual:(WeakValue *)object { return [self.nonretainedObject isEqual:object.nonretainedObject; }
    @end

And then a dealloc method that eventually calls a tiny block of code:
    
    WeakValue *key = [[WeakValue alloc] init];
    key.nonretainedObject = self; // It blows up at runtime here with "cannot form weak reference to instance" error
    [dictionaryWithWeakValueKeys removeObjectForKey:key];
Your WeakValue class is not safe to use as a dictionary key in any case. The fact that it holds a weak reference that it uses to implement equality (and thus hashing) makes it mutable, and using mutable objects as dictionary keys is a serious problem.

I think the only safe way to implement a weak dictionary key like this would be to use object identity rather than isEqual:, and have the value object cache its hash when it's created. You could then remove it by having a specialization that used __unsafe_unretained (completely safe as long as you don't message it).

Another, perhaps better, way would be to write your own dictionary class (e.g. starting with MAMutableDictionary from https://github.com/mikeash/MACollections) and having it use weak references directly, with the ability to locate and remove zeroed ones.
I don't believe your analysis of this code is correct:

    if(_weakBar)
        [self mustNotBeNil: _weakBar];


From:
http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime.objc_loadWeak
(Accessed 9/11/2012)

8.8. id objc_loadWeak(id *object);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.

If object is registered as a __weak object, and the last value stored into object has not yet been deallocated or begun deallocation, retains and autoreleases that value and returns it. Otherwise returns null. Equivalent to the following code:

id objc_loadWeak(id *object) {
  return objc_autorelease(objc_loadWeakRetained(object));
}
Must be atomic with respect to calls to objc_storeWeak on object.

Rationale: loading weak references would be inherently prone to race conditions without the retain.


This code:

   Bar *bar = _weakBar;
    if(bar)
        [self mustNotBeNil: bar];

however should result in a call to:

8.9. id objc_loadWeakRetained(id *object);

Precondition: object is a valid pointer which either contains a null pointer or has been registered as a __weak object.

If object is registered as a __weak object, and the last value stored into object has not yet been deallocated or begun deallocation, retains that value and returns it. Otherwise returns null.

Must be atomic with respect to calls to objc_storeWeak on object.


Via disassembling a quick test app in lldb, I confirmed that these are the calls being generated in both cases.

Thus, both versions of your code are safe, but for different reasons.
That's how it's currently implemented, but unless the documentation guarantees that such an object's lifetime is extended to that of the current autorelease pool, you can't count on it. Without such a guarantee, nothing says that Clang couldn't decide to implement the if check using objc_loadWeakRetained followed immediately by a release. If you're relying on Clang generating a call to objc_loadWeak without any guarantee that that's what it must do, you're leaving your code open to breaking in future compiler releases.
That's a fair point, but that's assured by a different section of the same documentation.

Reading occurs when performing a lvalue-to-rvalue conversion on an object lvalue.

For __weak objects, the current pointee is retained and then released at the end of the current full-expression. This must execute atomically with respect to assignments and to the final release of the pointee.
(emphasis mine)

Thus, you're guaranteed to have a valid pointer for the rest of your scope. (You're correct that the autoreleased nature of objc_loadWeak is not necessary to achieve the above specification. A hidden strong variable could suffice.)

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.semantics
"Full-expression" is not synonymous with a scope. It is roughly synonymous with "statement", expanded to also cover the expressions within control constructs like if statements, etc. See section 6.8 paragraph 4 of the C standard (or at least the one I have here) for the proper definition. The most relevant and clear part is probably:

The end of a full expression is a sequence point.

I'd never heard the term "full expression" in this context before, but we all know, or should know, what a sequence point is.

Your quoted documentation says that, in the code we're discussing, the loaded value from _weakBar will be released as soon as the if statement decides which branch to take. That the compiler is more lenient is entirely chance.
Looks like I equated "full-expression" to "scope" when I read that. Thanks for keeping me honest.

Also, Apple's got your back:
For non-trivial cycles, however, you should use:

MyViewController *myController = [[MyViewController alloc] init…];
// ...
MyViewController * __weak weakMyController = myController;
myController.completionHandler = ^(NSInteger result) {
    MyViewController *strongMyController = weakMyController;
    if (strongMyController) {
        // ...
        [strongMyController dismissViewControllerAnimated:YES completion:nil];
        // ...
    }
    else {
        // Probably nothing...
    }
};

http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW9
I'm finding it hard to get a good answer about blocks and copy under ARC. Apple says this in their "Transitioning to ARC Release Notes":

How do blocks work in ARC?

Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.


But you say that you don't need to copy unless it is being cast to id. So was it that Apple didn't want to get into the real reason you need copy (because arrayWithObjects doesn't know it is a block) or is it true that you need to use [block copy] anytime you hold onto a block (vs when you return it up up the stack)?

However, beware! ARC currently does not automatically copy a block literal that's converted to an id.



This seems to have been fixed by Apple by SDK 8.0, would you please verify this and note it on your article?

Thanks.

Comments RSS feed for this page

Add your thoughts, post a comment:

Spam and off-topic posts will be deleted without notice. Culprits may be publicly humiliated at my sole discretion.

Name:
The Answer to the Ultimate Question of Life, the Universe, and Everything?
Comment:
Formatting: <i> <b> <blockquote> <code>.
NOTE: Due to an increase in spam, URLs are forbidden! Please provide search terms or fragment your URLs so they don't look like URLs.
Code syntax highlighting thanks to Pygments.
Hosted at DigitalOcean.