Friday, June 29, 2012

RubyMotion tutorial - Button, text field and an alert box

This post shows you how to make an app that has the following flow:
  • Enter text your name in an input field.
  • Click a button and an alert box opens up to greet you.
 


Stuff you need to know

 

  • I’m assuming that you are comfortable with Ruby.
  • RubyMotion doesn’t support
    • require
    • autoload
    • define_method
    and a few more. So most of your rubygems turnout to be useless, unless you hack them bit.
  • UI elements in iOS have a frame. Think of it as the frame for a photograph on your wall. When you create elements, you have to specify the frame, in the following format:
    [[x, y], [width, height]]
  • You’ll be using the following UI elements
    • UIWindow
    • UITextField
    • UIButton
    • UIAlertView
  • iOS documentation is available here - http://developer.apple.com/library/ios/navigation/
  • Don’t hesitate to copy-paste code to try out things. That is exactly why code snippets are for. Go even further and make your own modifications.
  • I learnt RubyMotion a few hours before making this app and have never written an iOS app as of this blog post. So if you find something can be done in a better way, share your suggestions.
  • This post is in code-commentary style, so read the code too.

Here’s how we do it

 

This post is a bit lengthy because of the basics. So just hang on and the pastures on your side will turn green. Let’s create a new application using the motion command


 motion create click_to_greet
    Create click_to_greet
    Create click_to_greet/.gitignore
    Create click_to_greet/Rakefile
    Create click_to_greet/app
    Create click_to_greet/app/app_delegate.rb
    Create click_to_greet/resources
    Create click_to_greet/spec
    Create click_to_greet/spec/main_spec.rb



cd into the click-to-greet directory. All relative paths mentioned from now on will be relative to this directory.

 

AppDelegate


All your code must go into the app directory. This is how your app/app_delegate.rb looks like when your app is first generated:
class AppDelegate
  def application(application, didFinishLaunchingWithOptions:launchOptions)
    true
  end
end
The pattern is similar to the MVC pattern. And this app_delegate.rb is like the Rails routes file. It’s used to set the root controller for your application.
This the order of elements in the iOS UI.
UIScreen (the screen)
|
|__UIWindow (the window)
    |
    |__UIViewController
       |
       |__UIView (generally UI elements)
First, create a window for the application. And also set the root controller for it. Right now it’s just some class name and we’ll call it MainViewControler. So your app_delegate.rb should look like the following.
class AppDelegate

  def application(application, didFinishLaunchingWithOptions:launchOptions)
      
    # Get the frame for the window
    @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)

    # Instantiate a new object of the MainViewController
    # and assign it as the root controller.
    @window.rootViewController = MainViewController.new
        
    # This makes the window a receiver of events (for now we are using touch).
    @window.makeKeyAndVisible
        
    # Because this method must return true
    true
  end
  
end
Just like in Ruby, to instantiate an object of a class, you use the Class.new method. In iOS, you have to allocate memory to the object first and then initiate it. In RubyMotion, the Class.new method does the same as Class.alloc.init
iOS provides some helper class methods that allows you to do some tasks in a shorter way. So instead of instantiating an object and then assigning a frame to it like below.
@window = UIWindow.new
@window.frame = UIScreen.mainScreen.bounds
iOS provides the initWithFrame on UI elements. But this must be used with the alloc method, which is why you see:
@window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)
UIScreen.mainScreen.bounds returns the frame, that the main screen provides for applications.

 

MainViewController


Now for the MainViewController, create the file app/main_view_conroller.rb.
# You have to inherit from UIViewController
class MainViewController < UIViewController

  # Called to load the view
  # This is where you instantiate your view and set it as the controller's view.
  def loadView
    # Set the view for the controller
    # We don't need anything special for now. So we'll directly instantiate an object of UIView
    self.view = UIView.new
  end
  
  # Called after the view is loaded
  def viewDidLoad
    # A text input field instantiated with initWithFrame
    @input_field = UITextField.alloc.initWithFrame([[0, 0], [200, 40]])
    
    # Set the text color using the UIColor class which offers named colors
    @input_field.textColor = UIColor.blackColor
    
    # Set the background color for the text field
    @input_field.backgroundColor = UIColor.whiteColor
    
    # Set the border style of the text field to rounded rectangle
    # We need a rounded border, defined by the constant UITextBorderStyleRoundedRect
    @input_field.setBorderStyle UITextBorderStyleRoundedRect
    
    # Add the text field to the controller's view
    self.view.addSubview @input_field
    
    
    # Initiate button with button type
    @action_button = UIButton.buttonWithType UIButtonTypeRoundedRect
    
    # Set the title for the default UI state, which is normal
    # Normal UI state is defined by the constant UIControlStateNormal
     
 
       @action_button.setTitle "Greet me", forState: UIControlStateNormal
    
    # Set the frame for the button 
 
 
      @action_button.frame = [[100, 100], [100, 50]]
    
    # Add an event for the button when touched
    # 'self' refers to the handler class for the action in which the callback is defined
    # greet_user is the method is that'll be called when the event happens
    # The touch state is defined by the constant UIControlEventTouchUpInside 
 
          @action_button.addTarget(self, action: :greet_user, forControlEvents: UIControlEventTouchUpInside)
    
    # Add the button to the view 
 
    self.view.addSubview @action_button
  end
  
  # The touch callback for the button
 
  def greet_user
    # Instantiate an alert box with the title and a greeting message
    # And a text for the cancel button
    # Which will say "ok"
    # The arguments from the second to last, are not Ruby hash arguments
    # They are Objective-C style arguments.
    # You can't randomize the order or skip them if they are nil
    @alert_box = UIAlertView.alloc.initWithTitle("Greeting",
        message:"Hi #{@input_field.text}",
        delegate: nil,
        cancelButtonTitle: "ok",
        otherButtonTitles:nil)
    
    # Show it to the user
    @alert_box.show
  end
end

 

Run the app


Now that you’ve typed out the stuff required, run the rake command in the project’s directory. The iOS simulator should popup and showcase your app in all glory.

some basic Objective-C Tutorial

Objective-C is a programming language used in iPhone app development.


Objective-C Objects

           To define an object to work with you simply write out the name of the class and a name that will serve as the local pointer to the object:


 NSNumber *numberObject;
 
 
 NSNumber is a commonly used class in Objective-C and here our object is named numberObject. The asterisk is used to indicate that the object name is a pointer.

Messaging Objects

 When you need an object to do something in Objective-C you must send it a message. In other programming languages you may be used to “calling methods” with syntax that looks something like this:

 alert.show();
 
 
Objective-C handles this task a little bit differently by using this idea of messages and we will refer to this process as sending a message instead of calling a method. To demonstrate this syntax let’s stick with the example of an alert that we started with above.
To give some context, an alert is a common user interface element that pops up with a message for a user to read. In programming languages like dot net or Java you will probably call a method like “show” to invoke the behavior of alert that shows the message. To do the same thing with this object in Objective-C you would write this:


 [alert show];
 
 
The first thing you will notice is that the object and method are surround by square brackets. This is the trademark Objective-C syntax that people always notice and are sometimes vexed by. Secondly, check out how the method name is separated from the object here. In this context, we would refer to this statement as sending the “show” message to the “alert” object.


Messaging with Parameters

Often you will need to send a message that includes one or more parameters. In other programming languages this could look something like this:

 
 
alert.show("A Funny Message");alert.show("A Funny Message", 3);

In Objective-C we can do a similar thing, but we also get to include descriptive prefixes (specified in the class definition) to help us with code documentation. For example, here is how we would send messages like the ones above:
 
 
          [alert show:@"I say this!"];
 [alert show:@"I say this!" thisManyTimes:3];
 
 

Instantiating Objects in Objective-C

Before you work with an object in Objective-C you will need to create an local instance of the object. This process is called instantiating and when you are using Objective-C on the iPhone you will need to allocate memory as well as create an object. To allocate memory you send a alloc message to the class itself (you can send messages to both objects and classes).
To create the object itself, you will use a constructor that is generally prefixed with the word “init” or simply init. Here is how you instantiate an object (from now on I will be using generalized descriptive words for the various components in the examples):


myClass *myObject = [[myClass alloc] init];
 
 

Releasing Objects

When using Objective-C on the iPhone you must release objects that you have created using alloc, new or copy. This has to do with memory management which will be discussed in the next section. To release an object you simply send the “release” message to the object.
 
 
[myObject release];



Here is the pattern that you will typically follow when using objects in Objective-C:
 
 
 //allocate memory and create object
 myClass *myObject = [[myClass alloc] init];
 //Use object
 [myObject doStuff];
 //Release object
 [myObject release];
 

Memory Management and Reference Counting

When you are working with Objective-C on the iPhone you need to manage memory manually. This is a very detailed and important topic and if memory management is not done correctly then it could lead to memory leaks or app crashes.
Managing iPhone memory is a simple system called “reference counting”. The idea is that the system will keep track of whether it needs to keep the memory for an object available based on the number of other components that indicate that they want the object to stick around. Each component gets to indicate its interest in the object by adding a reference (sometimes called retain) count to the object.
You may add to an object’s reference count by sending the “retain” message to an object. So, if 5 components are interested in myObject then myObject has a reference count of 5. The system will keep your object’s memory in place as long as the reference count is above 0. As components no longer need an object to stick around they will remove their interest in the object by sending a “release” message to the object.
Each time a release message is sent to an object it’s reference count goes down by 1. Once the reference count reaches 0 the system may destroy the object and re-use the memory at any time.

Basic Memory Management


While reference counting is a simple system, it does require a lot of attention to detail and being consistent in how you handle this is very helpful. The most important thing to remember to do is to release every object that you create with the “alloc” keyword.

Every alloc must be matched with a release.

The other thing you must do is to make sure to match every retain message that you send to an object to a release message. Once you are finished with an object be sure that the reference count is 0. If you do this then you can be assured that you will not be wasting memory.
Every retain must be matched with a release
Do not send messages to objects that have been completely released and have a retain count of 0. If you do this your app may crash; this is the most common and vexing problems in app development. Here is an example of a typical life cycle of an object and it’s reference count during each step:

myClass *myObject = [[myClass alloc] init];
//Reference Count: 1

 [myObject retain];
 //Reference Count: 2

 [myObject retain];
 //Reference Count: 3

 [myObject release];
 //Reference Count: 2

 [myObject release];
 //Reference Count: 1

 [myObject release];
 //Reference Count: 0

Once myObject reaches a reference count of 0 at the end the system will destroy the object and if you attempt to send a message to myObject your app will crash. Notice how each alloc and retain is matched to a release. If you do not match alloc, new and retain messages with corresponding release messages you will either leak or crash your app.

Strings with NSString

Let’s move on to some classes and objects that are used frequently in Objective-C. Many of these come from Foundation which provides foundational programming functionality (sort of like it sounds). Check out the header files that come with XCode to see everything you can do with Objective-C. It provides a pretty rich framework. Moving on to strings: in Objective-C the class you use to work with string is called NSString and it is used like other objects:

NSString *myString = [[NSString alloc] initWithString:@"A String"];

NSLog(myString);

 [myString release];

NOTE: Above we use NSLog to write messages out to the console. Here we simply create an instance of NSString using the typical pattern describe above (alloc, init & release). However, NSString comes with additional functions that do not require you to use alloc or a release message. The same thing could be accomplished with this:

NSString *myString = @"A String";

 NSLog(myString);

NSString also has functions that will help you compose new strings by gluing other strings, numbers and objects together using the stringWithFormat function:

NSString *lotsOfInsertedStuffString = [NSString stringWithFormat:@"I am adding this number: %i and this string:%@.", 45, myString];

NSLog(lotsOfInsertedStuffString);


NSString comes with a rich feature set so be sure to look up the functions available to you in the header files.

Counting and Numbers in Objective-C

For the most part you may as well stick to using regular C style integers and doubles when doing math. Objective-C and C and often used together and working with numbers using int and double is much easier when doing math. You can use the Objective-C class NSNumber however when you need to style numbers in a particular way. You will also be using the C style for typical programming activities such as: looping, if-then logic, case statements, structs and functions. C Refresher for Integers and Doubles:

int i = 3;

NSLog(@"i = %i", i);

 double d = 3.4;

 NSLog(@"d = %f", d);

 double dPlusi = d + i;

 NSLog(@"d + i = %f", dPlusi);

Objective-C Arrays with NSMutableArray

Before we end let’s take a look at how to use the object oriented arrays that you have available from Foundation. Arrays are simply lists of objects and in Objective-C you can put anything into array and you can even mix and match objects. Here is how you generally use an array:

//Instantiate an array

 NSMutableArray *myArray = [[NSMutableArray alloc] init];

 //Add elements to an array
[myArray addObject:@"Element 1"];
 [myArray addObject:@"Element 2"];
 [myArray addObject:@"Element 3"];

 //Retrieve an object from an array

 NSLog([myArray objectAtIndex:0]);

 //Retrieve the last object in an array

 NSLog([myArray lastObject]);


One powerful reason to use arrays is that you can leverage the for-each loop which is a way of repeating the same action on every object in the array: for (NSString *s in myArray) { NSLog(s); } Of course, you must release the array object when you are finished (sorry for beating it in like this but it’s important!)

[myArray release];
 
 
 
 
 
 

Monday, June 18, 2012

Gmaps for rails 3

rails new gmaps

cd gmaps

rake db:create

rails g scaffold Location name:string address:string longitude:float latitude:float

In  app/view/layout,add the below
<!DOCTYPE html>
<html>
<head>
<%= yield :head %>
<title>GMaP</title>
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
</head>
<body>
<%= yield %>
</body>
<%= yield :scripts %>
</html>



In app/model/location.rb,add the below
class Location < ActiveRecord::Base
acts_as_gmappable
def gmaps4rails_address
address
end
def gmaps4rails_infowindow
“<h4>#{name}</h4>” << “<h4>#{address}</h4>”
end
end

In app/controllers/locations_controller.rb,add the below
def index
@locations = Location.all
@json = Location.all.to_gmaps4rails

In app/views/locations/index.html.erb,add the below
<%= gmaps4rails(@json) %>

In Gemfile,add the below
gem ‘gmaps4rails’,’0.7.7′

bundle install

rake db:migrate

rails s

http://localhost:3000/locations