- Objective-C Memory Management Essentials
- Gibson Tang Maxim Vasilkov
- 928字
- 2025-02-26 08:49:18
How ARC looks
Start by picturing a traditional Objective-C source code file written by an expert Cocoa programmer. The retain
, release
, and autorelease
messages are sent in all the right places and are in perfect balance.
Now, imagine editing the source code file, removing every instance of the retain
, release
, and autorelease
messages, and changing a single build setting in Xcode that instructs the compiler to put all the suitable memory management calls back into your program when the source code is compiled. That's ARC. It's just what the name suggests—traditional Cocoa reference counting, being automatically done.
At its core, ARC is not a runtime service; it doesn't work on program execution, as Garbage collection does. On the other hand, the new Clang, the compiler frontend for C, C++, Objective-C, and Objective-C++, provides it as a two-part phase (we will call these phases "cycles"). In the following diagram, you can see these two phases. At the cycle named frontend as shown in the following diagram, Clang will analyze every preprocessed file for properties and objects. And then, relying on a few fixed rules, it will insert the correct statements—retain
, release
, and autorelease
.

For instance, if an object is allocated and locally corresponds to a method, this object will have a release
statement close to that method's endpoint. This release
statement, if it is a class property, comes into the dealloc
method in a class, which can be your custom class or any Objective-C class. If it's a collection object or a return value, it will get an autorelease
statement. However, if it was referenced as weak, it will be left in peace.
The frontend also inserts retain
statements for disowned objects locally. It goes to every declared accessor and updates them with the directive @property
. It includes calls to the dealloc
routine of their superclasses such as NSObject
or UIViewController
or even your own customer
superclass. It will also report any explicit management call and double ownership.
In the optimize cycle, the modified sources are sent to load balancing by Clang. So, it calculates the retain and release calls created for each object, and reduces all to the optimal minimum. This action avoids excessive retain
and release
messages with the possibility to impact with full performance:
To see how it works, take a look at the following code: @class MyBar; @interface MyFoo { @private NSString *myOwnString; } @property(readonly) NSString *myOwnString; - (MyBar *)getMyBarWithString:(NSString *)myString; - (MyBar *)getMyBar; @end @implementation MyFoo; @dynamic myOwnString; – (MyBar *)getMyBarWithString:(NSString *)myString { MyBar *yBar; if (![self.myString isEqualToString:myString]) { myOwnString = myString; } return [self getMyBar]; } - (MyBar *)getMyBar { MyBar *yBar return yBar; } @end
Now, it's an Objective-C class with no retain
or release
. There is one private property named myOwnString
, which is an instance of NSString
. This class imports the header of the MyBar
class (line 1) and declares a read-only getter with the same name, myOwnString
. There is a modifier called getMyBarWithString
and an internal function named getMyBar
.
The following code is the same piece of code using Manual Reference Counting (MRC):
@class MyBar; @interface MyFoo { @private NSString *myOwnString; } @property (readonly) NSString *myOwnString; - (MyBar *)getMyBarWithString:(NSString *)myString; - (MyBar *)getMyBar; @end @implementation MyFoo; @dynamic myOwnString; – (MyBar *)getMyBarWithString:(NSString *)myString { MyBar *yBar; if (![self.myString isEqualToString:myString]) { [myString retain]; [myOwnString release]; myOwnString = myString; } return [self getMyBar]; } - (MyBar *)getMyBar { MyBar *yBar [yBar autorelease]; return yBar; } - (void)dealloc { [myOwnString release]; [super dealloc]; } @end
Note that the class interface is still the same. However, now, the getMyBarWithString
modifier has some new statements; more specifically, two:
[myString retain]; [myOwnString release];
Sending a release statement to the myOwnString
property (line 24) is the responsibility of one of them. The other sends a retain
message to the myString
argument (line 25). Before returning the last one as its result, the getMyBar
function sends locally a autorelease
statement to the yBar
local. Lastly, MRC supersedes the dealloc
method of that class. MRC also releases the myOwnString
property (line 44) and invokes the dealloc
method of its superclass (line 45); still in that method, if there is already a dealloc
method, MRC properly updates its code.
When using ARC, you don't need to explicitly insert retain
and release
messages, as ARC will automatically insert them during compilation. Since ARC decides by itself how an Objective-C object will be better managed, the time that will be required to develop the class code is not required anymore. So, ARC avoids any empty pointers. ARC can also be excluded on a per-file basis where you select your target, go to Build Phases, and add the -fno-objc-arc flag in Compiler Flags.
However, the Clang compiler is built into LLVM 3.0, only available on Xcode since version 4.2. There has been optimized runtime support for ARC ever since Mac OS X Version 10.7 and iOS Version 5.0. It is not challenging to use ARC with binaries from Mac OS X 10.6 and iOS 4.3, but for iOS 4.3, it's only achievable through blue code; and for OS X 10.6, the newest version does not make use of weak pointers at all.
Some points about ARC are as follows:
- It does not work with
AppleScriptObjC
or evenPyObjC
sources; it works exclusively with Objective-C sources. - However, more or less, when there are
PyObjC
andAppleScriptObjC
classes being connected to Cocoa by Objective-C code, ARC will affect that underlying code. - Note that for some third-party frameworks, if ARC is enabled, they might crash while compiling. Ensure that the developer of such a framework can and will update it.