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.