Winter is Coming

April 5, 2014

The legends speak of a man — more animal than man, really — who descended upon the web from the far north, slaying all in his path with powerful blog posts. Eventually, however, the n00bie iOS developers rose up and drove him away. They say that he has been slumbering for years, waiting for people to forget him, for complacency to set in, for the right season to return and wreak his vengeance.

That man was Mitch Cumstein, my roommate. He's a good man.

Anyway, I did actually write one or two things last year. At the time, I wasn't committed to writing more. But I knew I could not leave this world. I had to come back and … restore the legend. I can't update my old blog, for technical reasons. (Technically, laziness.) So I'm going to start a new blog. The new blog has an Atom feed that you can follow. No, that you must follow.

The New Hotness® in the Objective-C world is Automatic Reference Counting, or ARC for those who can't be bothered to type more than three characters. ARC will of course be deprecated in Xcode 6, but in the meantime Apple is encouraging everyone to waste time adopting it. As a Cocoa veteran, I've already mastered retain-release-autorelease, so in general I don't find much use for ARC. There is one notable exception, though: inside of blocks. Actually, it's not ARC in itself that we're interested in, it's zeroing weak references. ARC without zeroing weak references ("ARCLite") would not suffice for this purpose. The idea of Objective-C blocks is a good one, but Apple's implementation has one gigantic flaw. If you copy a block, then any use of self or an ivar inside of the block will cause the Objective-C runtime to automatically and silently retain self. This makes it way too easy for even experienced and careful programmers such as myself to accidentally create memory leaks via retain cycles. Unacceptable!

The block-weak-reference song-and-dance has been discussed elsewhere. In short, you would use this kind of pattern to avoid a retain cycle:

	id __weak weakSelf = self;
	_block = [^ {
		id strongSelf = weakSelf;
		if ( strongSelf != nil )
			[strongSelf doSomething];
	} copy];

According to the Objective-C Feature Availability Index (which I won't bother to link to here, because Apple inevitably breaks documentation links), the Mac requirements for ARC with zeroing weak references are OS X 10.7 and the modern runtime. The "modern runtime" is a roundabout way of saying x86_64, or 64-bit.

Suppose that you have a 64-bit app, and you want to use ARC. No problem. Now suppose that you want to put the ARC code in an existing framework dependency of your app. No problem. And suppose that you're not yet ready to switch your whole framework from MRR to ARC. No problem. Finally, suppose that the framework is shared by both 64-bit and 32-bit apps. Problem.

The ARCHS build setting for your framework includes both i386 and x86_64. The first thing you'll want to do is to put your ARC code in files that aren't used by your 32-bit apps. Next, you'll want to wrap your ARC code files with #if __LP64__ to conditionally compile the code for 64-bit. As a consequence, the files will simply be empty when compiling i386. Finally, ARC can be enabled for individual files with the -fobjc-arc compiler flag. In Xcode, you can set per-file flags under Build Phases in the Compile Sources build phase. The catch, for "fat" or "universal" builds that are both 32- and 64-bit, is that you cannot set your per-file flags to -fobjc-arc. Why not? Because the per-file compiler flag applies to every architecture, but -fobjc-arc is an invalid flag for i386. So your build will die.

The trick to enabling ARC for specific files in your framework is to use a per-architecture build setting. Create a User-Defined build setting, something like MY_FRAMEWORK_USE_ARC. Make the build setting empty. Then create a per-architecture variant of MY_FRAMEWORK_USE_ARC for Intel 64-bit, and set that variant to -fobjc-arc. You'll now be able to use $MY_FRAMEWORK_USE_ARC as the per-file flag in your build phase, and the flag will have the appropriate definition as each architecture is built.

You're welcome. Now you can thank the old blogs and the new. Sometimes it snows in April.