Using ARC in native extensions

Automatic Reference Counting (ARC) is a compiler-level feature. If you enable ARC in your code, the compiler will insert appropriate method calls to garbage collect your objects at the end of their lifetimes. If you are targeting iOS versions 5 and above it is enough to simply enable ARC in your Xcode project. The rest of the development workflow remains the same. The problem comes when you want to use ARC but want your application to run on iOS 4.x. This feature is not fully backward compatible with older versions of iOS. iOS 4.3 or earlier do not support the full range of capabilities ARC offers. To use ARC but at the same time target iOS 4.x, you would have to do a few more things.

First, enable ARC and set the deployment target to 4.x in Xcode. Enabling ARC forces the compiler to add the magic code to your files during compile time. Setting the deployment target to 4.x tells it that the final binary has to be compatible with older platforms. If you were developing a native application this step would be sufficient. However, if you are creating a native extension you need to do one more thing. Setting the deployment target to 4.x also tells the linker to link in a static library which will satisfy the symbol dependencies introduced by the compiler generated code. This library is called libarclite_iphoneos.a. If you do not set the deployment target to 4.x, this library will not be linked in and the loader will try to resolve these dependencies at runtime. Since these symbols are not present in iOS 4.x, your application will crash with an error message that looks like this:

dyld: lazy symbol binding failed: Symbol not found: _objc_retain
Referenced from:
/var/mobile/Applications/XXX.app/XXX
Expected in: /usr/lib/libobjc.A.dylib

However, in your case Xcode is not the one invoking the linker. Your extension will be linked in to the main application by the AIR packager (ADT). So you need to tell ADT to link in libarclite_iphoneos.a yourself. To do so add the following linker options to the platform options file when packaging your ANE:

-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/arc
-larclite_iphoneos

Here /Applications/Xcode.app is the default install directory for Xcode 4.3.  Change the path appropriately if you have installed Xcode somewhere else.

Note, specifying an absolute path to the Xcode install directory in the linker options introduces the dependency that Xcode has to be installed on the machine the final IPA is packaged in.

To summarize, here are the steps:

  1. Enable ARC for your static library project
  2. Set deployment target to 4.3 in Xcode
  3. When creating the ANE, add the following options to your platform options file:
    <option>-L/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/lib/arc
    </option>
    <option>-larclite_iphoneos</option>

Package the IPA with the ANE as usual.

Note,  you do not have to do any of the additional steps if you are not worried about backward compatibility. Just enable ARC for your project and set deployment target to whatever minimum version of iOS you want to build your app for.

References:

  1. Transitioning to ARC Release Notes
  2. Objective-C Feature Availability Index
  3. Apple Developer Forum: ld: duplicate symbol _objc_retainedObject on iOS 4.3 , but not on iOS 5.0