Automatic Reference Counting (ARC) in iOS (Part I)

iOS SDKPrior to iOS 5 SDK, memory management in Objective-C is a manual process where developers are solely responsible for handling memory allocation and release, and object lifecycles. Apple introduced Automatic Reference Counting (or ARC) in iOS 5 to simplify memory management and made memory management the job of the new LLVM compiler.

Objective-C Memory Management Policy

The best way to understand memory management in Objective-C is to think of object ownership (see Memrory Management Policy for more info). Here are the rules to memory management prior to ARC:

  • You own any object you create – Method names that include alloc, new, copy, or mutableCopy creates an object
  • You can take ownership of an object using retain – An object can have more than 1 owner
  • When you no longer need it, you must relinquish ownership of an object you own – As long as an object has 1 owner, it continue to exist. Ownership to the object is relinquished by calling release. When an object is no longer owned, it gets disposed by the system
  • You must not relinquish ownership of an object you do not own – This is a conventional rule. Break this rule and the app may crash

These rules still apply to ARC even though retain, release, and autorelease are no longer supported in the new model. In ARC the rules are fulfilled automatically in the background and is primarily handled by the compiler. The key to understanding ARC is to distinguish the difference between an object and an object (pointer) variable referencing that object. As soon as there are no owners (or variables pointing) to an object, the system disposes that object. Also it is important to note that there’s no garbage collection in Objective-C. ARC is a compiler-time feature where the compiler analyzes code and insert code to track the lifecycles of objects.

When an object (NSObject type or its subclass) is created, we can assign the object to a variable. In ARC, an object variable can have one of the following 4 ownership qualifiers:

  • __strong
  • __weak
  • __unsafe_unretained
  • __autoreleasing

In this blog post, we will review the first two qualifiers __strong and __weak in detail and save the latter two in the next blog post.

The __strong Qualifier

__strong is akin to retain in non-ARC and it’s the default qualifier of an object variable if no ownership qualifier is specified. The following code snippets are identical.

- (void)nonARC {
  id obj = [[MyClass alloc] init];
  [obj release];
}

- (void)ARC {
  // Obj has a strong reference to MyClass object so it owns
  // MyClass object.
  id obj = [[MyClass alloc] init];

  // When the object variable goes out of scope, the owner
  // is discarded and consequently relinquishing ownership of
  // MyClass object.
}

For __strong qualifier, we rely on variable assignment and the end of a variable scope to gain and relinquish object ownership respectively.

The __weak Qualifier

The __weak qualifier is akin to the assign keyword in non-ARC and is typically used to reference an object but claims no ownership on that object. A __weak qualified variable is automatically assigned to nil (effectively disposing the pointer variable) after the object it is pointing to is released. We can perform a conditional check on a __weak qualified variable. If the variable is nil, we know that the referenced object has already been disposed.

__weak qualified variable is useful for for referencing up a parent-child object hierarchy ie. a child object should only establish a weak reference to its parent. For example, a table view can be implemented in iOS by creating a UITableView object and assign it to a UIViewController. Both objects reference each other. UIViewController references UITableView via the view property while UITableView references UIViewController via the delegate property. If we qualify all referencing properties as __strong, we will get into a circular reference situation. Under such circumstances, even though the referencing object variables have gone out of scope, the objects themselves are still not properly disposed. Due to the circular strong reference, the system still thinks that the 2 objects are owned, leading to memory leaks. A detailed explanation of circular reference is available here.

Reference reference between UITableView and UIViewController

The best way to handle circular reference especially if there’s a clear parent-child object relationship is to use a strong/weak reference pattern. UIViewController owns the UITableView object, so it makes sense to qualify this reference with a __strong qualifier. On the other hand, the delegate property in UITableView should be qualified as __weak given that UITableView doesn’t own UIViewController but merely referencing it.

We will talk about __unsafe_unretained and __autoreleasing qualifiers in the next blog post.

Reference