Linking Against libarclite in Ruby Motion

I ran into this runtime error the other day when testing a Ruby Motion app on a device with iOS 5.1 installed:

-[__NSArrayI objectAtIndexedSubscript:]: unrecognized selector sent to instance

Everything had been working fine in iOS 6 and, previously, when testing in iOS 5.x. The change that introduced this issue was upgrading a vendored version of the Objective-C SDWebImage library. In the latest version, the developers started using indexer syntax on NSArray, which allows one to access the contents of an NSArray like this: arr[2] instead of the old syntax: [arr objectAtIndex:2].

As our team was using the iOS 6.0 SDK, compiling this code wasn’t an issue. The root of our problem was that arr[2] is effectively translated into [arr objectAtIndexedSubscript:2] at compile time. The - objectAtIndexedSubscript: method is implemented in iOS 6 on NSArray to behave just like objectAtIndex:. However, as we discovered earlier, it is not implemented in iOS 5.x.

After some digging, I learned that this is usually not an issue when compiling an app with ARC support using the 6.0 SDK due to the inclusion of the libarclite library at link time. This library, among other things, provides a shim implementation of [NSArray objectAtIndexedSubscript:]. By passing the flag -fobjc-arc during the link phase, this library will be included.

Now our problem was Ruby Motion doesn’t currently use the -fobjc-arc flag during linking unless the deployment target is less than 5.0. But, I found a way to sneak a flag into the link phase:

Motion::Project::App.setup do |app|
  app.libs << "-fobjc-arc"

With this in place, we were back up and running on iOS 5.x and 6.0.

p.s. Using rake --trace was very useful for seeing all the commands being run (and verifying the inclusion of -fobjc-arc) thanks to Ruby Motion’s diligent use of the sh helper.