Understanding Automatic Reference Counting in Objective-C
By Paul on September 7th, 2011 in TechnobabbleTags: arc, development, iOS, ios5, xcode
Automatic Reference Counting (ARC) largely removes the burden of manual memory management, not to mention the chore of tracking down bugs caused by leaking or over-released objects! Despite its awesomeness, ARC does not let you ignore memory management altogether.
This post covers the following key aspects of ARC to help you get up and running quickly.
- Reference Counted Memory: Quick Revision
- How Automatic Reference Counting Works
- Enabling ARC in Your Project
- New Rules Enforced by ARC
- ARC Qualifiers – Declared Properties
- ARC Qualifiers – Regular Variables
- Migrating Existing Projects to ARC
- Including Code that is not ARC Compliant
- Should I Use ARC?
What Has Changed?

In the time before ARC, you had to manually retain/release/autorelease objects to ensure they would “stick around” for as long as you needed them. Forgetting to send retain to an object, or releasing it too many times would cause your app to leak memory or crash.
In Xcode 4.2, in addition to syntax checking as you type, the new Apple LLVM compiler makes it possible to offload the burden of manual memory management to the compiler, introspecting your code to decide when to release objects. Apple’s documentation describes ARC as follows:
“Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management) in Cocoa applications.”
This feature makes the memory management trivial most of the time, but you still need to take some responsibility for how your classes manage references to other objects.
Let’s start at the beginning …
Reference Counted Memory: Quick Review
Manually managed, reference counted memory works in iOS as follows: when creating an object using alloc/init (or other similar method), the object is returned with a retainCount of 1, meaning you havetaken ownership of the object.
NSObject *obj = [[NSObject alloc] init]; // do some stuff [obj release];
In between alloc/init’ing an object (i.e. taking ownership) and releasing an object (i.e. relinquishing ownership), you can do with it as you wish, safe in the knowledge the object will not be deallocated whilst still in use.
Similarly, by adding an object to an autorelease pool, your object will stick around when needed and be deallocated sometime in the future when no longer needed.
-(NSObject*) someMethod {
NSObject *obj = [[[NSObject alloc] init] autorelease];
return obj; // will be deallocated by autorelease pool later
}
How Automatic Reference Counting Works
Most programmers new to iOS have trouble getting their heads around reference counted memory. ARC is a pre-compilation step that adds retain/release/autorelease statements to your code for you.
This is not Garbage Collection, and reference counted memory has not disappeared, it has simply been automated. It may sound like a bit of an after thought, but considering how many features in Objective-C are implemented by pre-processing source files before compiling, ARC is really par for the course.
When writing code with ARC enabled your code will look like this:
NSObject *obj = [[NSObject alloc] init]; // do some stuff
The ARC pre-compilation step will auto-magically turn it into this:
NSObject *obj = [[NSObject alloc] init]; // do some stuff [obj release]; // **Added by ARC**
The diagram below (from Apple’s documentation) seems to imply that writing operative code takes almost as long to write as retain/release logic. Whilst this is not true for experienced Objective-C coders, it is probably a conservative estimate if you are new to Objective-C. Also, when they do pop-up, memory problems can be a PITA to track down.

Source: Programming With ARC Release Notes
Enabling ARC in Your Project
To enable ARC simply set the Objective-C Automatic Reference Counting option in your Xcode project’s Build Settings to YES. Behind the scenes this sets the -fobjc-arc compiler flag that enables ARC.

New Rules Enforced by ARC
There are a few rules you need to abide by in order to compile with ARC enabled.
1. Alloc/Init Objects
As described above, creating objects is done as before, however you must not make anyretain/release/autorelease/retainCount calls. You also cannot be sneaky by calling their selectors indirectly: use of @selector(retain) and @selector(release) are prohibited.
2. Dealloc Methods
Generally these will be created for you. You must not make a dealloc call directly. However you can still create a custom dealloc method if you need to release resources other than instance variables. When creating a custom dealloc method, do not call the [super dealloc] method. This will be done for you and is enforced by the compiler.
3. Declared Properties
Before ARC, we told the compiler how to memory manage declared public properties using theassign/retain/copy parameters with the @property directive. These parameters are no longer used in ARC. Instead we have the weak/strong parameters to tell the compiler how we want our properties treated.
4. Object Pointers in C Structures
This is also a taboo. The docs suggest storing them in a class instead of a struct. This makes sense since they would otherwise be unknown to ARC. It might cause extra some migration headaches. However, ARC can be disabled on a file by file basis. See the section on “Including Code that is not ARC Compliant” below.
5. Casual Casting Between id and void*
Casting between id and void* data types is frequently done when handing objects between Core Foundation’s C library functions and Foundation Kit’s Objective-C library methods. This is known asToll Free Bridging.
With ARC you must provide hints/qualifiers to tell the compiler when CF objects are moving into and out of its control for memory management. These qualifiers include __bridge, __bridge_retain and__bridge_transfer. Also you still need to call CFRetain and CFRelease to memory manage Core Foundation objects.
This is a more advanced topic, so if you don’t know what CF objects are, don’t worry for now.
6. @autoreleasepool instead of NSAutoReleasePool
ARC compliant code must not use NSAutoReleasePool objects, instead use the @autoreleasepool{}blocks. A good example is in the main.m file of any ARC compliant/migrated project.
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([ExampleAppDelegate class]));
}
}
7. Other Gotchas
Zone based memory is gone (apparently it’s not in the runtime anymore either); you cannot use NSAllocateObject or NSDeallocateObject.
ARC Qualifiers – Declared Properties
As programmers, we are used to making decisions like whether to make something a variable or a constant, locally or globally defined, etc. So too, we must decide how our properties relate to other objects. We use the strong/weak qualifiers to notify the compiler of these relationships.
Strong References
A strong reference is a reference to an object that stops it from being deallocated. In other words it creates a owner relationship. Whereas previously you would do this:
// Non-ARC Compliant Declaration @property(retain) NSObject *obj;
Under ARC we do the following to ensure a class instance takes an ownership interest a referenced object (i.e. so it cannot be deallocated until the owner is).
// ARC Compliant Declaration @property(strong) NSObject *obj;
Weak References
A weak reference is a reference to an object that does not stop it from being deallocated. In other words, it does not create an owner relationship. Whereas previously you would do this:
// Non-ARC Compliant Declaration @property(assign) NSObject *parentObj;
Under ARC you would do the following to ensure you do not “own” the object being referred to (e.g. typically a child object should not own its parent, so we would use a weak reference).
// ARC Compliant Declaration @property(weak) NSObject *parentObj;
ARC Qualifiers – Regular Variables
Variable Qualifiers
The above examples illustrate declaring how our declared properties should be managed. For regular variables we have:
__strong __weak __unsafe_unretained __autoreleasing
Generally speaking, these extra qualifiers don’t need to be used very often. You might first encounter these qualifiers and others when using the migration tool. For new projects however, you generally you won’t need them and will mostly use strong/weak with your declared properties.
- __strong – is the default so you don’t need to type it. This means any object created usingalloc/init is retained for the lifetime of its current scope. The “current scope” usually means the braces in which the variable is declared (i.e. a method, for loop, if block, etc…)
- __weak – means the object can be destroyed at anytime. This is only useful if the object is somehow strongly referenced somewhere else. When destroyed, a variable with __weak is set tonil.
- __unsafe_unretained – is just like __weak but the poiner is not set to nil when the object is deallocated. Instead the pointer is left dangling (i.e. it no longer points to anything useful).
- __autoreleasing, not to be confused with calling autorelease on an object before returning it from a method, this is used for passing objects by reference, for example when passing NSError objects by reference such as [myObject performOperationWithError:&tmp];
Source: LLVM Clang Objective-C Automatic Reference Counting Documentation
NB: We have found @property declarations using ‘retain’ with ARC enabled (i.e. instead of ‘strong’) do not cause compiler warnings and yield the same compiled result. This could change in future so stick to ‘strong’ for clarity.
Migrating Existing Projects to ARC
Xcode 4.2 provides a conversion tool that migrates existing code to ARC, and helps you manually convert code that cannot be automatically migrated.
1. Open your non-ARC compliant project and go to Edit > Refactor > Convert to Objective-C ARC.

2. Select the build targets and contained files to convert (you exclude files in laters steps too)

3. Run Precheck and press next.

NB: When you press next the LLVM compiler will build the project in order to analyse it. If your project has any errors, you cannot proceed to the next step. If you are opening a project from a previous Xcode version for the first time, remember to Clean.
4. Inspect the proposed changes and choose to include/exclude any files. Then press save.

NB: You will also be notified of any files that cannot be migrated. Not all files (including existing libraries) need to be migrated. ARC works on a file by file basis, so see the section below on how to exclude them at compile time.
5. The migration tool will automagically set the compiler flag enabling ARC to on. You can confirm this in your project’s build settings (search for ‘reference counting’).
Including Code that is not ARC Compliant
According to Apple’s documentation: “ARC interoperates with manual reference counting code on a per-file basis. If you want to continue using manual reference counting for some files, you can do so.”
This means some files can use ARC and some files can be spared from it’s magical grasp. Here are the steps for bulk excluding files from ARC at compile time. At the time of writing, many popular libraries are not ARC ready, to get around this follow these steps:
- Click on your Project in the Xcode project tree
- Click on the Target
- Select the Build Phases tab
- Expand the Compile Sources section
- Select one or more files you want to exclude from ARC
- Press the return key
- Type -fno-objc-arc
- Press the return key again
- Each file selected now has a -fno-objc-arc compiler flag set and will be excluded from ARC
Should I Use ARC?
If you are new to Objective-C, you will certainly welcome it. There is more than enough to learn at first without worrying about reference counted memory. Once you start using existing libraries though, you are sure to experience pain until you get accustomed to explicitly excluding them from ARC pre-compilation.
If you’re already coding happily without ARC, you’re probably thinking “I don’t need it!” This may be the right answer for you — for now. Most popular libraries haven’t been converted to ARC and it does not play well with Core Foundation classes. There are specific limitations when using CF classes listed in Apple’s documentation, and a bunch of extra qualifiers are needed to make Toll Free Bridging work when migrating code.
From what I have seen and read, ARC is ready to use right now. However, it is probably best left to new projects until you get familiar with it. Whilst ARC is backwards compatible with iOS 4.0 onwards, weak references are only supported in iOS 5.0 onwards — possibly another reason not to migrate everything just yet (there are work arounds to this, see the “Resources” section at the bottom of this post).
Performance wise, some early reports claim ARC can make your projects faster – possibly due to less reliance on autorelease. However, you can also do that yourself by “coding better” and using retain/release more judiciously. But that’s just the point: ARC should always choose the most optimised approach for your code automatically.
Right now there is some pain involved in moving to ARC, but not a lot. At Long Weekend we will leave it for new projects at first, but this is Apple’s “new” recommended approach, so you can be sure future design decisions will build on ARC and move further away from manual reference counting.
ARC Resources:
- Apple’s ARC Programming Release Notes
- Clang documentation on LLVM complier ARC
- Work around for supporting zeroing weak references in iOS 4 and OS X 10.6
- Managing Toll Free Bridging Between Objective-C & Core Foundation Objects
- WHAT is Toll Free Bridging?
- Chris Lattner’s WWDC2011 Presentation Introducing ARC (ADC Members Only)
Other iOS Resources
If you are looking to learn more about iOS development, you might be interested in our post on the resources we used. You might also like some of our other blog articles on development.





42 Responses to “Understanding Automatic Reference Counting in Objective-C”
James says:
Thanks for the info. I’m trying to convert my project to an ARC managed project but I’m having some issues. After I run the conversion tool 0 files have been changed. Basically all the tool is doing is changing the build setting for my project to build as an ARC project. Then I get a ton of build errors for every use of retain, release, and autorelease. Ever seen this or know what could be causing it?
I’m targeting iOS 4.0 but I even tried converting while targeting iOS5 but no luck.
Any ideas?
Thanks!
Oct 23, 2011 | Reply
Paul says:
@James: It sounds like the migration tool is changing theARC build setting, but not changing any of your files. Are you using version control like Git or SVN? Does it show changes to any source files post running the converter? If not, then I’d refollow the steps above, making sure your screens look like the ones included.
Oct 25, 2011 | Reply
Paul says:
@James: I read that after clicking “save” if nothing happens, your Xcode might be failing when creating the project snapshot.
According to http://www.daveoncode.com a clean install can solve this a la: “sudo /Developer/Library/uninstall-devtools” and installing Xcode anew.
Alternatively you may want to turn off code snapshot in File > Project Settings > Snapshots.
If this isn’t the case for you then pls ignore.
Oct 25, 2011 | Reply
James says:
Hey Paul. No changes have been made to any of the file, except for the ARC setting in the project & target. I’ve tried going through the procedure several times with the same result.
Oct 26, 2011 | Reply
James says:
@paul
I went through my project and manually removed all calls to retain, release, autorelease and autorelease pools. The project works fine now. It was a huge pain however. I had over 900 errors in the project after running the arc tool. But it’s done now! Thanks for your help though.
Oct 26, 2011 | Reply
Paul says:
No problem, you certainly learned more about ARC by doing it that way.
Oct 26, 2011 | Reply
kc says:
Hyey man thanks for your great post! it was awfully informative and is exactly what I needed. Although One thing I noticed when I went through and migrated the existing project files to ARC compatible and then I went through to the steps whee you include code that is non ARC compliant, they already had -fno-objc-arc next to their values in the compile section.. maybe this is something new that apple has done to make the process easier for adding 3rd party wrappers etc.
again many thanks.
Nov 1, 2011 | Reply
Juan González says:
Hi Paul, great post. I’m getting into this world and this was a great way to understand the way ARC works.
Keep the good work.
Nov 1, 2011 | Reply
Gabriele says:
In ARC mode, is there any reason to use @autoreleasepool ? In which cases is it still needed to explicitly use it ?
Thanks.
Nov 3, 2011 | Reply
Paul says:
@gabriele: The @autoreleasepool syntax replaces the old way to explicitly create autorelease pools using code like this:
In ARC you will still call convenience methods like [NSString stringWithFormat:@"..."] that return an autoreleased object. These objects will stay in memory until the pool is drained. So you may need to create a localized autorelease pool to avoid having too many autoreleased objects in memory when optimizing your app.
By my understanding, ARC helps you avoid leaks, but not running out of memory. That’s still up to you.
Nov 3, 2011 | Reply
Paul says:
@kc: interesting feedback. I tried replicating by creating a new project without ARC and then selectively converting only some of the files. The files not converted did not have a -fno-objc-arc compiler flag set automatically.
Not sure the exact process you took to get there, but the -fno-objc-arc doesn’t seem to be added automatically every time, so just in case, the instructions in the post are handy.
Nov 3, 2011 | Reply
Paul says:
@juan, np. Some advice: ARC does not free us from understanding how reference counted memory works, but it does help avoid leaky code.
We still need to appreciate the difference between autoreleased objects & non-autoreleased objects, strong/weak references, retain cycles, etc…
Nov 3, 2011 | Reply
Clint says:
Thanks for the great post. It was very informative and well written!
Nov 10, 2011 | Reply
George Cook says:
What a great article. Thank you so much for so generously sharing your knowledge.
All the best,
Nov 26, 2011 | Reply
Dktahara says:
Thanks for your post! Definitely helped me with my iPhone App.
Dec 22, 2011 | Reply
Dktahara says:
Thanks for your explanation! Definitely helped me with my iPhone app!
Dec 22, 2011 | Reply
Tarang says:
cool I am starting to understand ARC now.
I think you are missing just one extra step when enabling the ARC i.e. to select the Apple LLVM compiler otherwise it do not show the Objective-C Automatic Reference Counting option.
Let me know if I am wrong but that is what I saw.
Jan 19, 2012 | Reply
Rajesh says:
Nice article..Good introduction to ARC! Thanks !
Feb 22, 2012 | Reply
vishnu says:
thanks:this helps me allot.
Mar 12, 2012 | Reply
Linh says:
Thanks for your info. What’s is the difference between ARC and autorelease message?
May 22, 2012 | Reply
Paul says:
@Linh: ObjC on iOS uses manual memory management which involves using the following “messages” to manage the lifecycle of an object: retain / release / autorelease / copy / mutablecopy
With ARC, the pre-compiler works out were to put all these in for you, so long as you follow a few rules as outlined above.
The method “autorelease” should not be used in ARC. For completeness I should explain that autorelease adds your object to an autorelease pool, which is a list of objects that are periodically released en masse by the framework, removing the need for you to do it manually somewhere in your code.
May 24, 2012 | Reply
Brent says:
__unsafe_unretained – is just like __weak but the poiner is not set to nil when the object is deallocated. Instead the pointer is left dangling (i.e. it no longer points to anything useful).
Dangling Pointer?? I thought this led to memory leaks!
Nov 3, 2012 | Reply
Paul says:
> Dangling Pointer?? I thought this led to memory leaks!
@Brent: it can lead to memory leaks (hence the name “unsafe”) but __weak is only available under ARC (ie. iOS 5.0 and OS X Lion deployment targets or newer). Whereas __unsafe_unretained works under previous versions of iOS/OS X.
Nov 5, 2012 | Reply