Automatic Reference Counting

Automatic Reference Counting (ARC) is one of two memory and object lifetime management models used by the Elements compiler, next to Garbage Collection (GC). It is used on the Cocoa platform.

Automatic Reference Counting manages object life cycles by keeping track of all valid references to an object with an internal retain count. Once all references to an object go out of scope or are cleared, and the retain count thus reaches zero, the object and its underlying memory is automatically freed.

In essence, ARC (as well as GC) alleviates the developer of the burden of manually keeping track of object ownership, eliminating explicit calls to "free" or "destroy" methods or so-called destructors.

Cocoa Only

ARC is used on the Cocoa platform only. The .NET and Java platforms use Garbage Collection, as does Island except when using Cocoa or Swift objects.

Retain Cycles

While ARC provides a more deterministic destruction of objects than GC, one downside of ARC is that it cannot automatically handle Retain Cycles, that is cyclic references between two or more objects that "keep each other alive". The concepts of Storage Modifiers and object references has been introduced to compensate for that.

Auto-Release Pools

Under the hood, ARC uses the concept of so-called Auto-Release Pools to help manage the life cycle of unowned objects returned from functions. In most cases, auto-release pools are created for you by the Cocoa runtime, as it calls into your application. However, Elements does provide a syntax for explicitly creating auto-release pools, should you need them, via the do keyword combination.

Method Naming Rules

Cocoa uses special naming rules to determine if the result of a called method is returned "owned" (i.e. needs to be released by ARC when it goes out of scope) or unowned (i.e. needs to be retained by ARC if it is held onto beyond the current scope in a reference). Since ARC takes care of all of this, in general the developer no longer needs to be aware of these naming conventions much — however, care must be taken when naming new methods.

The following method name prefixes are known by ARC to return retained objects. In general, you should avoid implementing methods with these names, except when overriding methods from NSObject or implementing Constructors and "init*" Methods. If you must declare methods that break these conventions, the [ReturnsNotRetained] special attribute can be applied to the method to indicate that despite the name, it returns an unretained object.

init*, alloc*, copy*, mutableCopy* and new* return owned objects by default, i.e. have [ReturnsRetained] implied.

Conversely, the [ReturnsRetained] special attribute can be used to indicate a method that returns an owned object, in spite of not using the above naming.

The compiler will automatically adjust the ARC code generated inside methods adorned with these attributes, so that the reference count of the returned object is as expected. E.g. in a method marked with [ReturnsRetained], ARC will ensure that the result value is not released or placed in the autorelease pool.

Comparing GC and ARC

You can find a more detailed comparison of GC and ARC, and how the differences affect the Elements code you write, in the Automatic Reference Counting vs. Garbage Collection topic.

Elements' ARC Compared to Objective-C

In essence, Elements's ARC implementation works identical to that provided by the Objective-C language in the Clang-LLVM compiler; as a matter of fact, it uses the same underlying runtime mechanisms.

One item worth noting is that in contrast to Objective-C's default, Elements considers local variables to go out of scope at the end of the block that defined them (i.e. usually at the end of the method, or at the end of a nested/pair). By contrast, Objective-C will release the references stored in local directly after the last time that variable is accessed, which can lead to some unexpected crashes when working with child objects or bridged objects.

In Objective-C, the __attribute__((objc_precice_lifetime)) attribute can be used to change this behavior; Elements behaves as if this attribute was defined, by default. You could say that Elements errs on the side of caution and more well-defined object lifetimes.