RubyMotion Tutorial for Beginners: Part 1

In this RubyMotion Tutorial for beginners, you’ll learn how to make a simple Pomodoro app for the iPhone. By Gavin Morrice.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

The “app” Directory

app is where most of your application’s code should live; you’ll store your views, controllers, and models there. RubyMotion will automatically load all files in this directory with a .rb extension.

The “build” Directory

build by default will contain all of your compiled code; you create it the first time you run rake against your project. However, you can specify an alternate directory for your compiled code in the build_dir parameter of your Rakefile.

From time to time you might want to clear the build directory and rebuild the whole application from scratch; simply run rake clean within your project directory in Terminal to accomplish this.

The “resources” Directory

resources is where you add any extra resources to your bundle, including icons, images, fonts and other files.

The “spec” Directory

spec is where you store specs, or tests, for your app. The Ruby community has a long-established culture of writing well-tested code, which includes writing the tests before writing any code.

You won’t cover Ruby tests in this tutorial — that’s a whole other subject best left for another time! :]

Hello World Example

No tutorial would be complete without a “Hello World” example, and this one is no exception.

Open app/app_delegate.rb and add the following lines above application:didFinishLaunchingWithOptions:

def hello_world_label
  @hello_world_label ||= begin
    frame = CGRectMake(20,200,280,40)
    label           = UILabel.alloc.initWithFrame(frame)
    label.text      = "Hello world"
    label.textColor = UIColor.whiteColor
    label.textAlignment = UITextAlignmentCenter
    label
  end
end
    
def window
  @window ||= UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
end

Here’s what the above code does:

First, you define a method named hello_world_label, which is a getter method for a UILabel that the app will display on the screen. Unlike a standard getter though, which would simply return the value of @hello_world_label, this method goes a step further. The ||= (or-equals) operator here means “if the variable on the left is truthy return its value; otherwise execute the code to the right of the operator and assign its value to the variable for future calls”.

This is a great way to lazy-load a property in that its value is only set when you actually call the method; in addition, this is a memoized method which caches its value, making future calls to this method execute faster.

Next, you define a method named window, which returns the main UIWindow object for this application. Again, you use the ||= operator to set a default value if one is not already set.

Note: The name of this method is hello_world_label, not helloWorldLabel as you might be used to seeing. Why?

In Objective-C, you usually write method variable names in CamelCase; in Ruby it’s general practice to write them in snake_case. Since RubyMotion is a hybrid between the two, you’ll often see RubyMotion developers use either CamelCase or snake_case: there doesn’t seem to be an agreed upon convention.

What’s my preference? Both! :] When writing code that’s part of the iOS API such as when defining a tableView:cellForRowAtIndexPath method, I’ll use CamelCase — even for the parameters — since that’s how it was defined in the API. I’ll use snake_case with code that’s specific to the application. This clearly delineates my code from iOS API code — and it means I can re-use my plain old Ruby classes in other non-RubyMotion applications without having to modify them.

Note: The name of this method is hello_world_label, not helloWorldLabel as you might be used to seeing. Why?

In Objective-C, you usually write method variable names in CamelCase; in Ruby it’s general practice to write them in snake_case. Since RubyMotion is a hybrid between the two, you’ll often see RubyMotion developers use either CamelCase or snake_case: there doesn’t seem to be an agreed upon convention.

What’s my preference? Both! :] When writing code that’s part of the iOS API such as when defining a tableView:cellForRowAtIndexPath method, I’ll use CamelCase — even for the parameters — since that’s how it was defined in the API. I’ll use snake_case with code that’s specific to the application. This clearly delineates my code from iOS API code — and it means I can re-use my plain old Ruby classes in other non-RubyMotion applications without having to modify them.

Still in the same file, update application:didFinishLaunchingWithOptions: so that it looks like the following:

def application(application, didFinishLaunchingWithOptions: launchOptions)
  window.addSubview(hello_world_label)
  window.makeKeyAndVisible
  true
end

Here you add hello_world_label as a subview to the window object and tell the application to make the window object visible.

Save your work, then switch over to Terminal and run the following command:

rake

In a few seconds you’ll see your shiny new RubyMotion “Hello World” app running in the iOS Simulator as below:

RW_Rubymotion_Hello

Type exit in Terminal to stop both Rake and the simulator.

That takes care of your Hello World app; you can now take your new-found knowledge and press on with building Pomotion.

Adding a Main View Controller

Your first task in Pomotion is to create a main view-controller for the main screen.

To keep things organized — and to stay in line with Ruby on Rails’ file structure — you’ll create a new directory to store your controller files.

Return to Terminal and run the following command:

mkdir app/controllers

This creates a new directory controllers inside the existing app directory.

Run the following command in Terminal:

touch app/controllers/main_view_controller.rb

This creates a new file for your view controller.

Open main_view_controller.rb and add the following code:

class MainViewController < UIViewController
end

The code above creates a class MainViewController that inherits from UIViewController. Note that you've kept the same name for your controller class as the file that contains your class.

Next, return to app_delegate.rb and delete the entire hello_world_label method along with the code you added in application:didFinishLaunchingWithOptions:; they won't be required for Pomotion.

Your complete app_delegate.rb should now look like this:

class AppDelegate
  def window
    @window ||= UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
  end
  
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    true
  end
end

Now, add the following code to app_delegate.rb:

def main_view_controller
  @main_view_controller ||= MainViewController.alloc.initWithNibName(nil, bundle: nil)
end

def navigation_controller
  @navigation_controller ||= UINavigationController.alloc.
    initWithRootViewController(main_view_controller)
end

Here you simply create getter methods for the MainViewController and a UINavigationController to present it.

Finally, add the following to application:didFinishLaunchingWithOptions::

def application(application, didFinishLaunchingWithOptions:launchOptions)
  window.rootViewController = navigation_controller
  window.makeKeyAndVisible
  true
end

In the code above you tell window to display navigation_controller and become visible.

Run rake in Terminal to launch the simulator:

RW_Rubymotion_BlankVC

For now, all you'll see is a UINavigationBar with a blank screen; The window is loading navigation_controller as expected, but the displayed view is transparent.

One option is to create them in code, like you'll do in this tutorial. A second option is to use Interface Builder with RubyMotion - to learn how to do that, check out this GitHub page.

Note: One of the key benefits of RubyMotion is that it can be used independently of Xcode. However, what do you do for user interfaces?

One option is to create them in code, like you'll do in this tutorial. A second option is to use Interface Builder with RubyMotion - to learn how to do that, check out this GitHub page.

Gavin Morrice

Contributors

Gavin Morrice

Author

Over 300 content creators. Join our team.