My migration to ARC (Automatic Reference Counting), using Xcode 4.2 refactor assistant

Starting from Xcode 4.2 and the introduction of the new LLMV compiler, is now possible to use “Automatic Reference Counting” (ARC). This powerful feature frees developers from memory management by eliminating the need of sending release and autorelease messages. Anyway this is very different from a garbage collector, in that it’s a compile-time feature, which basically analyze the code and automatically inserts that calls when necessary for us. In this way we have the best of two worlds: we don’t have to worry about releasing, deallocations and memory leaks, but simultaneously we have the performance of a memory managed language. This is very cool, however I don’t envy new upcoming iOS developers whose will start directly using ARC. It’s very important learning and understanding how memory management works in Objective c, and the difference between owning a reference to an object or not (I recommend this reading). For example I fear that new developers won’t understand the use and benefits of NSAutoreleasePool (that have been replaced with @autorelease block in ARC).
Anyway in the last days I switched my code to ARC using Xcode refactor system and I want to share my experience.
These are the steps I followed:

1. “Preferences” -> “General” -> check “continue building after error”

This step is fundamental to avoid an huge waste of time repeating the next steps every time an error is encountered!

2. “Edit” -> “Refactor” -> “Convert to Objective-C ARC”

3. “Select targets to convert” (check them)

4. Click “precheck”

5. “Cannot Convert to Objective-C ARC” (Xcode found N issues that prevent conversion from proceeding. Fix all ARC readiness issues and try again.)

You will see this message at least once, because your code contains calls that are forbidden by ARC.

6. Fix them using suggestions (click on errors to open the popup containing the tip). Then repeat from step 1

7. “Convert to automatic reference counting” window will appear (once issues have been fixed)

8. Click next

9. Review automatic changes

10. Save

If after clicking on “save” nothing happens, you may be unlucky as I am and Xcode is unable to prooced because it silently fails trying to generate a snapshot of your project. I solved the problem by doing a clean install, that means run “sudo /Developer/Library/uninstall-devtools” to remove all files and install Xcode from the scratch (by the way this had also improved its performances).

The migration was pretty painless in my case, however I had to disable ARC on certain files because it was very hard to refactor the code in order to make it ARC-friendly (this is the case for heavy use of Core Foundation functions).
To disable ARC in these files I added the flag “-fno-objc-arc” in the column “compiler flags” under “Build phases” tab (related to my target).
I then did a small refactor by marking NSError pointer as “autoreleasing”:

NSError *__autoreleasing error = nil;

This is in fact a little optimization trick, that avoid the creation of an extra temporary variable by the compiler. (read more here).

I also marked all readonly properties as “strong” and removed the “__unsafe_unretained” placed by Xcode.

…that’s all folks… all works pretty well, the code is shorten and cleaner and I’m satisfied :)

13 thoughts on “My migration to ARC (Automatic Reference Counting), using Xcode 4.2 refactor assistant

  1. Dave,

    Question – I’m trying to exclude some 3rd party files with -fno-objc-arc. I set those values under my target-build phases-select the file-set that value for a file’s compiler flag. I run “Edit” -> “Refactor” -> “Convert to Objective-C ARC”, I get the dialog to select the project, the project runs and the build fails on the files that I used -fno-objc-arc on and those compiler flags values disappear before the Cannot Convert to Objective-C ARC dialog appears.

    I’m at wit’s end.

    Sure could use some thoughts on the matter.

    Kind regards,

    John

  2. try this: remove the files you don’t want to be converted (by removing I mean remove them from “compile sources” in the Build phases, not physically!), then run the refactor assistant and finally, when you are able to convert your project to ARC add those files again and specify the “-fno-objc-arc” flag… I hope this will works :P

    …let me know ;^)

  3. Dave says:

    Removing the files from compile sources does not work, as references to the classes in other headers (eg imports variable defintions etc) stop working causing compiler errors.

  4. Byron says:

    John, Dave:

    I was having the same problem. I finally noticed that when you click Edit –> Refactor –> Convert to Objective-C ARC, the dialog that pops up “Select Targets to Convert” has a disclosure triangle to the left of the project name, which you can click to get the list of files belonging to the project. Then, just deselect any classes that you do not want the migration tool to consider.

    Hope that helps!

  5. found it says:

    So the issue you couldnt save a snapshot. In xcode do file->create snap shot. it willgive u an error. usualy ur .gitignore is blocking a file and needs -f. anyways do
    1-edit .gitignore, remove offending line
    2-refactor
    3-put .gitignore back to normal

    note after #2 it works. ur welcome!!

  6. hristo says:

    I had the same issue with snapshots not getting created. Trying File -> Create Snapshot would fail complaining about .gitignore and .DS_Store files.

    Going to my project directory first and then running:
    find . -name “.DS_Store” -depth -exec rm {}\;

    got rid of the .DS_Store files and I was able to create snapshots after that

  7. Jingjie says:

    The first one saves me tons of time when I’m trying to convert Amazon SDK to ARC. Thanks!

  8. nandhu says:

    i am trying to convert the code the way u wrote. but the xcode shows all release, retain calls as errors. should I delete them. If i have to delete them, what would the conversion tool actually do?

  9. Vaibhav says:

    Yes…Remove’em All…
    ex.
    [xyz release];
    [xyz init]autorelease];

    //No need to use retain.. while you use ARC.

Leave a Reply