Search
Rich's Mad Rants
Powered by Squarespace

Entries in RubyMotion (1)

Thursday
May172012

RubyMotion and Storyboards: two great tastes that taste great together

Ok, I'll admit it. I'm very excited by RubyMotion--the new framework that lets us write Ruby-based applications for our iOS devices. I've long been a huge fan of MacRuby, and I've been waiting impatiently for it to show up on iOS. I'm not sure how they managed it, but HipByte made the magic happen, and I purchased a developer's license as soon as I learned about it.

Unfortunately, my first impressions were somewhat tempered. Don't get me wrong, I loved the Ruby bits--I just wasn't that excited about building my interfaces by hand. Yes, I could use Xcode to create nib files and copy them into my project's resources directory--but that seemed like a lot of work…especially as the number of nibs grew.

However, RubyMotion is moving at near-light speed. In the few weeks since release, we've already seen four updates, and I must say, RubyMotion 1.4 made me giggle like a school girl. This update added support for Storyboards. Suddenly RubyMotion became a lot more useful to me.

To test out the new Storyboard integration, I've created a silly proof-of-concept project. It doesn't do anything useful, other than act as a test bed for trying various Storyboard fatues. Still, I'm quite pleased with the results. The process remains a bit more manual than I'd like--but it's a huge improvement over dealing with multiple nibs, or (shudder) building everything by hand.

There are a few steps that may not be obvious, so I'm going to quickly walk through everything at a high-level. For more details, be sure to check out the source code. It's small, and everything should be obvious. As always, if you have questions, just leave them in the comments.

Building the App

First things first, I could simply create a storyboard file with Xcode, and layout all my scenes. However, this would be largely useless. Yes, I can draw the segues and relationships. I can even change the view controller classes to the correct Ruby classes. However, I cannot connect my outlets or actions.

The problem is, Xcode doesn't know anything about my Ruby classes--so it cannot know which actions and outlets are available. Therefore, I have to make an entire Xcode project, and then create stub classes for my Ruby classes (at least, for any class with an outlet or action). I can then define the actions and outlets in these stub classes, and draw connections to my heart's content.

Note: The Xcode project doesn't need to compile or run. I just need header files with the proper IBOutlet and IBAction tags.

Once we have a completed storyboard, simply copy the storyboard file into our RubyMotion project's resources directory. You'll have to repeat this step any time you modify the storyboard. Usually, rake will detect the new storyboard file and update everything with the next build--however, if you're not seeing the expected changes, make sure you actually saved the storyboard, then copy it again. Delete the previously compiled version (it will also be in the resources directory, and will end in "c"), and then execute rake clean, just to be safe.

With the storyboard in place, I simply created Ruby classes whose names matched the class stubs in the Xcode project. Then I create their outlets and actions.

For outlets, I simply declared attributes with matching names:

attr_accessor :label, :textField, :delegate

Similarly, Actions are just methods. If an action method in the Objective-C header looks like this:

- (IBAction)textChanged:(id)sender;

The RubyMotion equivalent will be:

def textChanged(sender)

  # do something here

end

Next, I need to load the storyboard when the app launches. In an Xcode project, this would be defined in the info.plist. In RubyMotion, we can set those values in the Rakefile:

app.info_plist['UIMainStoryboardFile'] = 'MainStoryboard'

Finally, my app delegate needs to implement the window property. Oddly enough, I cannot use attr_accessor :window for this. Instead, I must explicitly create the required accessor methods:

def window

  @window

end

 

def setWindow(window)

  @window = window

end

And, that's it. The storyboard-based app is good to go.

If you have any interest in Ruby and iOS, then I'd strongly recommend giving RubyMotion a look. Yes, the developer license is a bit steep. If you need a free trial, you can always play around with MacRuby on the OS X side--however, honestly, I think RubyMotion feels more slick and solid at the moment. Especially since I can't seem to get MacRuby's Xcode integration to work with the new App-store version of Xcode.

Note: If you look at my Rakefile you will see that I've explicitly set the codesign_certificate. Typically, you won't need to do this. However, I have multiple code sign certificates on my laptop, and by default, RubyMotion selects the wrong one.