Chris Zetter

Adventures in RubyMotion: The App Store in 2 weeks

I had been wanting to build an app for a while and recently had the time to do so. Here’s why I choose RubyMotion and what I found it to be like.

I’d tried picking up Cocoa programming before to write OSX and iOS apps but never got that far. The volume of what I had to learn to get started meant I never had enough time to become proficient and productive.

Here are the most important skills you have to learn for iOS programming:

Let’s go though them and see why I went with RubyMotion.

Objective C vs Ruby

I already know and love Ruby so it’s great that I can use it on iOS too. I don’t mind Objective-C, though managing header files can feel tedious at times and the calling syntax and method signatures take a while to get used to as they differ a lot from other C-like languages.

Ruby is an incredibly terse & expressive language so you’ll end up with cleaner source without a lot of boiler-plate. For example, to pad a string with exclamation marks in Objective-C:

[@"Hello" stringByPaddingToLength: 9 withString: @"!" startingAtIndex: 0]

The same using ljust method in the Ruby standard library:

"Hello".ljust(9, '!')

Ruby has some incredibly useful methods in it’s core classes making them richer than their Objective C counterparts. Look at String (vs NSString), Array (vs NSArray), Hash (vs NSDictionary) and Integer (vs NSNumber).

There are a couple of changes RubyMotion had to make to the core of the language to make it compatible with Cocoa APIs.

Changes to semantics

In objective C a method name includes all the named arguments, so the string padding method we saw above is named: stringByPaddingToLength:withString:startingAtIndex:

Ruby 2.0 supports keyword arguments which allows RubyMotion to support a similar calling style:

"hello".stringByPaddingToLength(9, withString: '!', startingAtIndex 0)`

However, unlike Objective C, Ruby named arguments don’t become part of the method names so in core Ruby we can only ever have one stringByPaddingToLength method. RubyMotion has bent the semantics of the Ruby to allow multiple methods with the same name as long has they have different keywords arguments. You’ll appreciate why this was necessary if you look at UITableViewDelegate- all the methods begin with tableView.

JRuby has a similar problem when interfacing with Java. Java supports method overloading- multiple methods can be defined with the same name but different type signatures. JRuby solves it by passing type information to java_send.

Pass by reference

Some Cocoa method arguments are passed by reference. This is common when a method has to return multiple values, such as the method getHue:saturation:brightness:alpha: on UIColor. To use this method you have to create pointers using the Pointer class provided by RubyMotion.

color = UIColor.greenColor
hue = Pointer.new(:float)
saturation = Pointer.new(:float)
brightness = Pointer.new(:float)
alpha = Pointer.new(:float)
color.getHue(hue, saturation: saturation, brightness: brightness, alpha: alpha)
puts "hue is #{hue.value}"

After calling getHue, the object hue points to is set to the hue of the colour. You can access it with hue.value or hue[0].

BYOTE (Bring Your Own Text Editor)

Xcode proudly flies in the face of the ‘do one thing and do it well’ philosophy. When you start it up for the first time and create a project there’s an overwhelming set of panels, toolbars and icons on display. Books on OSX and iOS programming are often filled with screenshot after screenshot of Xcode UI only to become outdated when Apple releases the next version.

With RubyMotion you can use whatever text editor you want and don’t have to run Xcode at all. You use rake tasks to build, simulate and test your app.

While building my app I only started Xcode to use Interface Builder. Using Interface builder makes it easier to see the collection of UI objects available and how setting properties on each one changed appearance. I didn’t use any code Interface Builder generated, instead using teacup because I liked the separation of styling it allows.

Cocoa

There’s no escaping Cocoa. You’re going to have to pick up some of the core classes and patterns to use RubyMotion effectively.

For a tour of some important Cocoa classes and patterns I found Clay Allsopp’s RubyMotion book really helpful.

Rubymotion does help in bypassing bits of Cocoa knowledge. First you can use methods on Ruby’s core classes (String, Integer, Array, etc) rather than their Cocoa counterparts. Secondly there are a lot of gems that wrap Cocoa functionality in a concise and ruby-like way, most notably BubbleWrap.

But don’t shy away from picking up Cocoa, if you ever want to ditch RubyMotion it’s the Cocoa knowledge which is going to be useful when you’re using Xcode and Objective C.

App Delivered

SuperLocate (after waiting 11 days for approval from Apple) is now in the App Store.

There are downsides to Rubymotion. As a paid-for closed source application you’re reliant on HipByte for any fixes and updates. I was impressed by how quickly and regularly updates appeared after each Xcode 5.0 developer preview for iOS 7.

RubyMotion is be a great choice for anyone who has Ruby knowledge that wants to build for iOS and OSX. I’ve since opened Xcode again and the Cocoa understanding I got from RubyMotion has made it feel a lot less daunting.

Read more by me, follow me on Mastodon or subscribe.