Home > Articles > Programming > C/C++

  • Print
  • + Share This
From the author of

A New Memory Model

My favorite part of ARC is not the automatic reference counting itself, but the fact that it includes a cleanup of the Objective-C memory model. Older Objective-C included a lot of hangovers from the very first implementations of Objective-C as a preprocessor that generated C. Objective-C objects back then were just C structures with a pointer to their class in the first field. Object pointers were just pointers to which you can send messages.

Now, the Objective- part of the language is properly separated from the C part. You can no longer implicitly cast between object and non-object types. When you explicitly cast, you must specify the ownership transfer.

Object pointers now fall into one of four categories: strong, weak, autoreleasing, and unsafe unretained. In non-ARC mode, all object pointers fall into the last category; it is your responsibility to ensure that they are safe.

Strong pointers—the default—are roughly equivalent to what would happen if you wrote perfect defensive retain/release code. They store owning references, so assigning to one is equivalent to retaining the new value, then releasing the old one.

Autoreleasing pointers are used to store values that are autoreleased. These formalize the most common form of non-owning pointer in Objective-C: variables on the stack that store values that have been autoreleased. When you store an owning reference to an autoreleasing variable, it will be autoreleased. When you store an autoreleased reference, you get a simple assignment.

You can use the __autoreleasing type qualifier to reduce the number of retain and release operations in a critical code path, but it's generally not needed and it can end up making things slower, because objects will be added to the autorelease pool, while ARC can often eliminate this.

The final pointer category is weak. If you've used garbage-collected mode, then you've probably seen weak pointers in Objective-C before. When you store an object in one, it doesn't count as an owning reference, and will be set to nil when the object is deallocated.

One of the biggest differences between ARC and GC mode is that ARC is deterministic, and you can see this with weak pointers. Consider this snippet:

    id strong = [NSObject new];
    __weak id weak = strong;
    strong = nil;
    NSLog(@"%@", weak);

First, this won't even compile in GC mode, because __weak is not allowed for on-stack variables in GC mode. If you move the declaration of weak somewhere that is valid, what will happen? Probably, the log statement will happily show you that the object is still alive, even though its last reference has gone. If you force the collector to run, then it may still see references on the stack, depending on the optimizations that the compiler runs.

In ARC mode, this snippet will compile—weak variables are now permitted on the stack—and it will always do exactly what you expect. Storing nil in strong will delete the last reference to the object and will trigger its destruction. This will zero the weak reference.

Weak references are supported by version 1.5 or later of the GNUstep Objective-C runtime, by iOS 5 and later, and by OS X 10.7 and later. The rest of ARC also works via a compatibility library on older versions of OS X, but weak references require modification to various classes, so can't easily be supported by a compatibility shim.

  • + Share This
  • 🔖 Save To Your Account