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 :)

Getting right UIImage and CGImage pixel size according to device display (retina or not)

I just fixed an issue related to the wrong display of an UIImageView in my (never ending WIP) app. The problem is that starting with iOS 4 and with the introduction of retina display in iPhone 4, the attribute “size” does not return the real pixel dimensions but points. So on a retina display device an image of 100×100 pixel will return a size of 200×200 (values are doubled). Theoretically there is an helpful attribute “scale” that should return a float value representing the adopted scale (2.0f for retina display, 1.0f for other).
Unfortunately, in my case it returns always 1, both for the iOS simulator than the real device (iPhone 4 with iOS 5), and my images are rendered incorrectly.
After digging on Google (which as usual points me to my beloved Stackoverflow), I gathered several helpful informations that helped me solving the problem and inspired a few helpful precompiler macros :)
The scale value, which is essential to implement retina display-aware software can be retrieved using:

[[UIScreen mainScreen] scale];

So, I realized the following macros:

// return true if the device has a retina display, false otherwise
#define IS_RETINA_DISPLAY() [[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2.0f

// return the scale value based on device's display (2 retina, 1 other)
#define DISPLAY_SCALE IS_RETINA_DISPLAY() ? 2.0f : 1.0f

// if the device has a retina display return the real scaled pixel size, otherwise the same size will be returned
#define PIXEL_SIZE(size) IS_RETINA_DISPLAY() ? CGSizeMake(size.width/2.0f, size.height/2.0f) : size

Then I used a little trick, to initialize an UIImage with the correct dimensions. Fundamentally I initialize an “helper image” first from which extract a CGImage in order to allocate a new UIImage using the initializer initWithCGImage:scale:orientation: (as scale I use the previous defined macro DISPLAY_SCALE).

UIImage *helperImage = [[UIImage alloc] initWithData:data];
UIImage *pic = [[UIImage alloc] initWithCGImage:helperImage.CGImage scale:DISPLAY_SCALE orientation:UIImageOrientationUp];

Invalid attempt to access ALAssetPrivate past the lifetime of its owning ALAssetsLibrary… WTF?

After the upgrade to iOS 5 and a code refactoring to make use of ARC, I was testing my app and receiving a strange error:

invalid attempt to access ALAssetPrivate past the lifetime of its owning ALAssetsLibrary

this because, I wasn’t aware of an ALAssetsLibrary‘s fact: (quote from Apple’s reference)

The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance.

This line of text should be displayed inside a warning box to catch developers attention, in fact it is an essential point to understand to create a reliable application that access to device’s media library! The point is that we have to ensure that an instance of ALAssetsLibrary is persisted in memory until we make use of ALAssets retrieved with it. To ensure this, I added a static method to retrieve a shared instance of that class (more or less like a singleton):

+ (ALAssetsLibrary *)defaultAssetsLibrary {
	static dispatch_once_t pred = 0;
	static ALAssetsLibrary *library = nil;
	dispatch_once(&pred, ^{
		library = [[ALAssetsLibrary alloc] init];
	return library; 

So, I can refer to it using [MyAssetsManager defaultAssetsLibrary] through my classes and I can use threads (NSOperations an NSOperationQueues) without having to use “trick” like performSelectorOnMainThread.