1. iOS and OS X

From this part of the document we will refer to the RubyMotion runtime as the one that powers iOS and OS X RubyMotion projects.

1.1. Object Model

The object model of RubyMotion is based on Objective-C, the underlying language runtime of the iOS and OS X SDK. Objective-C is an object-oriented flavor of C that has been, like Ruby, heavily influenced by the Smalltalk language.

Sharing a common ancestor, the object models of Ruby and Objective-C are conceptually similar. For instance, both languages have the notion of open classes, single inheritance and single dynamic message dispatch.

RubyMotion implements the Ruby object model by using the Objective-C runtime, the library that powers the Objective-C language and indirectly, the iOS SDK APIs.

In RubyMotion, Ruby classes, methods and objects are Objective-C classes, methods and objects respectively. The converse is also true. Objective-C classes, methods and objects are available in Ruby as if they were native.

By sharing the same object model infrastructure, Objective-C and RubyMotion APIs can be interchangeable at no additional performance expense.

1.1.1. Objective-C Messages

RubyMotion lets you send and define Objective-C messages.

An Objective-C message, also called a selector, can look different than a typical Ruby message, if it contains more than one argument.

Unlike Ruby messages, Objective-C messages contain keywords. Each argument has a keyword associated to it and the final Objective-C message is the combination of all keywords.

Let’s take the following piece of Objective-C code which draws a string.

[string drawAtPoint:point withFont:font];

In this code, string, point and font are variables. The message keywords are drawAtPoint: and withFont:. The complete message is the combination of these keywords, drawAtPoint:withFont: , which is sent to the string object, passing the point and font objects as arguments.

Objective-C messages can be sent from RubyMotion using a similar syntax.

string.drawAtPoint(point, withFont:font)

It is important to keep in mind that the message being sent here is drawAtPoint:withFont:. To illustrate more, the same message can be manually dispatched using the send method.

string.send(:'drawAtPoint:withFont:', point, font)

Objective-C messages can also be defined in RubyMotion. Let’s imagine we are building a class that should act as a proxy for our drawing code. The following piece of code defines the drawAtPoint:withFont: message on the DrawingProxy class.

class DrawingProxy
  def drawAtPoint(point, withFont:font)
    @str.drawAtPoint(point, withFont:font)
  end
end
Tip The syntax used to define Objective-C selectors was added to RubyMotion and is not part of the Ruby standard.

1.1.2. Objective-C Interfaces

As Objective-C is the main language used to describe the iOS SDK, it is necessary to understand how to read Objective-C interfaces and how to use them from Ruby.

Objective-C interfaces can be found in Apple’s iOS API reference and also in the iOS framework header (.h) files.

An Objective-C interface starts with either the minus or plus character, which is used to respectively declare instance or class methods.

For example, the following interface declares the foo instance method on the Foo class.

@class Foo
- (id)foo;
@end

The next one declares the foo class method on the same class.

@class Foo
+ (id)foo;
@end
Note (id) is the type information. Types are covered in an upcoming section, so you can omit them for now.

As seen in the previous section, arguments in Objective-C methods can be named with a keyword. The sum of all keywords form the message name, or selector.

The following interface declares the sharedInstanceWithObject:andObject: class method on the Test class.

@class Test
+ (id)sharedInstanceWithObject:(id)obj1 andObject:(id)obj2;
@end

This method can be called from Ruby like this.

# obj1 and obj2 are variables for the arguments.
instance = Test.sharedInstanceWithObject(obj1, andObject:obj2)

1.1.3. Selector Shortcuts

The RubyMotion runtime provides convenience shortcuts for certain Objective-C selectors.

Selector Shortcut

setFoo:

foo=

isFoo

foo?

objectForKey:

[]

setObject:forKey:

[]=

As an example, the setHidden: and isHidden methods of UIView can be called by using the hidden= and hidden? shortcuts.

view.hidden = true unless view.hidden?

1.1.4. Super

In Objective-C, super sends a message to the superclass of the current class, invoking a specific method. In the example below, super would send the play message to MediaController with song as the argument.

@interface VideoController : MediaController
@end

@implementation VideoController
- (void)play:(NSString *)song {
  [super play:song];
  // Customize here...
}
@end

In Ruby (and by extension, RubyMotion), super sends a message to the superclass of the current class, invoking a method of the same name and passing it the same arguments.

class VideoController < MediaController
  def play(song)
    super
    # Customize here...
  end
end

In Objective-C it is possible to call a method on the super class and bypass the method locally. This is especially convenient when defining init methods.

@interface CustomView : UIView
@property (copy) NSString *text;
@end

@implementation CustomView
- (id) initWithFrame:(CGRect)frame {
  [super initWithFrame:frame];
  self.text = @"";
  return self;
}
- (id) initWithText:(NSString*)text {
  UIFont *font = [UIFont systemFontOfSize:12];
  CGRect size = [text sizeWithFont:font];
  // skip local initializer
  [super initWithFrame:{{0, 0}, size}];
  self.text = text;
  return self;
}

This is a contrived example because in this case it would be fine to call initWithFrame. But there are cases where you do not want to call your local method, but you need to call the method on super.

This is not easily accomplished in Ruby (see How do I call a super class method on stack overflow). In Ruby you need to alias the parent method and call that method instead.

class CustomView < UIView
  alias :'super_initWithFrame:' :'initWithFrame:'
  # if your method takes multiple arguments, you can alias that as well
  # alias :'renameWithArg1:arg2' :'methodWithArg1:arg2'

  def initWithFrame(frame)
    super.tap do
      @text = ''
    end
  end

  def initWithText(text)
    font = UIFont.systemFontOfSize(12)
    size = text.sizeWithFont(font)
    super_initWithFrame([[0, 0], size]).tap do
      @text = text
    end
  end
end

1.2. Builtin Classes

Some of the built-in classes of RubyMotion are based on the Foundation framework, the base layer of iOS and OS X.

The Foundation framework is an Objective-C framework, but due to the fact that RubyMotion is based on the Objective-C runtime, the classes that it defines can be naturally re-used in RubyMotion.

Foundation class names typically start with the NS prefix, which arguably stands for NeXTSTEP, the system for which the framework was originally built.

Foundation comes with the root object class, NSObject, as well as a set of primitive object classes. In RubyMotion, Object is an alias to NSObject, making NSObject the root class of all Ruby classes. Also, some of the built-in classes inherit from Foundation types.

Here is a table showing the ancestors chain of a newly created class, Hello, as well as some of the Ruby built-in classes.

A direct consequence of hosting the Ruby built-in classes on Foundation is that instances respond to more messages. For instance, the NSString class defines the uppercaseString method. Since the String class is a subclass of NSString, strings created in Ruby also respond to that method.

'hello'.uppercaseString # => 'HELLO'

Conversely, the Ruby interface of these built-in classes is implemented on their Foundation counterparts. For example, Array's each method is implemented on NSArray. This allows primitive types to always respond to the same interface, regardless of where they come from. each will always work on all arrays.

def iterate(ary)
  ary.each { |x| p x }
end

iterate [42]
iterate NSArray.arrayWithObject(42)

But the main purpose of this design is to allow the exchange of primitive types between Objective-C and Ruby at no performance cost, since they don’t have to be converted. This is important as most of the types that will be exchanged in a typical application are likely going to be built-in types. A String object created in Ruby can have its memory address passed as the argument of an Objective-C method that expects an NSString.

1.2.1. Mutability

The Foundation framework ships a set of classes that have both mutable and immutable variants. Mutable objects can be modified, while immutable objects cannot.

Immutable Foundation types in RubyMotion behave like frozen objects (objects which received the freeze message).

As an example, changing the content of an NSString is prohibited and an exception will be raised by the system if doing so. However, it is possible to change the content of an NSMutableString instance.

NSString.new.strip!           # raises RuntimeError: can't modify frozen/immutable string
NSMutableString.new.strip!    # works

Strings created in RubyMotion inherit from NSMutableString, so they can be modified by default. The same goes for arrays and hashes.

However, you must be aware that it is very common for iOS SDK APIs to return immutable types. In these cases, the dup or mutableCopy messages can be sent to the object in order to get a mutable version of it, that can be modified later on.

1.3. Interfacing with C

You do not need to be a C programmer in order to use RubyMotion. However, some understanding of basic notions explained in this section will be required.

Objective-C is a superset of the C language. Objective-C methods can therefore accept and return C types.

Also, while Objective-C is the main programming language used in the iOS SDK, some frameworks are only available in C APIs.

RubyMotion comes with an interface that allows Ruby to deal with the C part of APIs.

1.3.1. Basic Types

C, and indirectly Objective-C, has a set of basic types. It is common in iOS SDK APIs to accept or return these types.

An example are the following methods of NSFileHandle, which both respectively accept and return the C integer type, int.

- (id)initWithFileDescriptor:(int)fd;
- (int)fileDescriptor;

Basic C types cannot be created from Ruby directly, but are automatically converted from and to equivalent Ruby types.

The following piece of code uses the two NSFileHandle methods described above. The first one, initWithFileDescriptor:, is called by passing a Fixnum. The second one, fileDescriptor, is called and a Fixnum is returned back to Ruby.

handle = NSFileHandle.alloc.initWithFileDescriptor(2)
handle.fileDescriptor # => 2

This table describes all basic C types and discusses how they are converted from and to Ruby types.

C Type From Ruby to C From C to Ruby

bool

If the object is false or nil, false, otherwise, true. Note: the 0 fixnum will evaluate to true.

Either true or false.

BOOL

char

If the object is a Fixnum or a Bignum, the value is returned. If the object is true or false, 1 or 0 are respectively returned. If the object responds to the to_i message, it is sent and the result is returned.

Either a Fixnum or a Bignum object.

short

int

long

long_long

float

If the object is a Float, the value is returned. If the object is true or false, 1.0 or 0.0 are respectively returned. If the object responds to the to_f message, it is sent and the result is returned.

A Float object.

double

When using an API that returns the void C type, RubyMotion will return nil.

1.3.2. Structures

C structures are mapped to classes in RubyMotion. Structures can be created in Ruby and passed to APIs expecting C structures. Similarly, APIs returning C structures will return an instance of the appropriate structure class.

A structure class has an accessor method for each field of the C structure it wraps.

As an example, the following piece of code creates a CGPoint structure, sets its x and y fields, then passes it to the drawAtPoint:withFont: method.

pt = CGPoint.new
pt.x = 100
pt.y = 200
'Hello'.drawAtPoint(pt, withFont: font)

It is possible to pass the field values directly to the constructor.

pt = CGPoint.new(100, 200)
'Hello'.drawAtPoint(pt, withFont: font)

RubyMotion will also accept arrays as a convenience. They must contain the same number and type of objects expected in the structure.

'Hello'.drawAtPoint([100, 200], withFont: font)

1.3.3. Enumerations and Constants

C enumerations and constants are mapped as constants of the Object class.

For instance, both NSNotFound and CGRectNull, respectively an enumeration and a constant defined by Foundation, can be directly accessed.

if ary.indexOfObject(obj) == NSNotFound
  # ...
end
# ...
view = UIView.alloc.initWithFrame(CGRectNull)
Important Some enumerations or constants defined in the iOS and OS X SDK may start with a lower-case letter, like kCLLocationAccuracyBest (starting with k). Because Ruby constants must always start with a capital letter, their names must be corrected by changing the case of the first letter, becoming KCLLocationAccuracyBest (starting with K) in Ruby.
locationManager.desiredAccuracy = kCLLocationAccuracyBest # NameError: undefined local variable or method
locationManager.desiredAccuracy = KCLLocationAccuracyBest # works

1.3.4. Functions

C functions are available as methods of the Object class. Inline functions, which are implemented in the framework header files are also supported.

As an example, the CGPointMake function can be used in Ruby to create a CGRect structure.

pt = CGPointMake(100, 200)
'Hello'.drawAtPoint(pt, withFont: font)
Important Most functions in the iOS and OS X SDK start by a capital letter. For those who accept no argument, it is important to explicitly use parentheses when calling them, in order to avoid the expression to be evaluated as a constant lookup.
NSHomeDirectory   # NameError: uninitialized constant NSHomeDirectory
NSHomeDirectory() # works

1.3.5. Pointers

Pointers are a very basic data type of the C language. Conceptually, a pointer is a memory address that can point to an object.

In the iOS and OS X SDK, pointers are typically used as arguments to return objects by reference. As an example, the error argument of this NSData method expects a pointer that will be set to an NSError object in case of failure.

- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(NSError **)errorPtr

RubyMotion introduces the Pointer class in order to create and manipulate pointers. The type of the pointer to create must be provided in the new constructor. A pointer instance responds to [] to dereference its memory address and []= to assign it to a new value.

The NSData method above can be used like this in Ruby.

# Create a new pointer to the object type.
error_ptr = Pointer.new(:object)

unless data.writeToFile(path, options: mask, error: error_ptr)
  # De-reference the pointer.
  error = error_ptr[0]

  # Now we can use the `error' object.
  $stderr.puts "Error when writing data: #{error}"
end

In the case above, we need a pointer to an object. Pointer.new can also be used to create pointers to various types, including the basic C types, but also structures.

Pointer.new accepts either a String, which should be one of the Objective-C runtime types or a Symbol, which should be a shortcut. We recommend the use of shortcuts.

Following is a table summarizing the pointers one can create.

C Type Pointer Runtime Type String Shortcut Symbol

id *

"@"

:object

BOOL *

"B"

:bool / :boolean

char *

"c"

:char

unsigned char *

"C"

:uchar

short *

"s"

:short

unsigned short *

"S"

:ushort

int *

"i"

:int

unsigned int *

"I"

:uint

long *

"l"

:long

unsigned long *

"L"

:ulong

long long *

"q"

:long_long

unsigned long long *

"Q"

:ulong_long

float *

"f"

:float

double *

"d"

:double

RubyMotion supports the creation of structure pointers, by passing their runtime type accordingly to Pointer.new, which can be retrieved by sending the type message to the structure class in question. For instance, the following snippet creates a pointer to a CGRect structure.

rect_ptr = Pointer.new(CGRect.type)

Pointers to C characters, also called C strings, are automatically converted from and to String objects by RubyMotion.

1.3.6. Function Pointers and Blocks

C or Objective-C APIs accepting C function pointers or C blocks can be called by RubyMotion, by passing a Proc object instead.

Functions pointers are pretty rare in the iOS and OS X SDK, but C blocks are common. C blocks are an extension of the C language defined by Apple. The caret (^) character is used to define C blocks.

As an example, let’s consider the addObserverForName:object:queue:usingBlock: method of NSNotificationCenter, which accepts a C block as its last argument.

- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue
      usingBlock:(void (^)(NSNotification *))block;

The block in question returns void and accepts one argument, a NSNotification object.

This method can be called from Ruby like this.

notification_center.addObserverForName(name, object:object, queue:queue,
  usingBlock:lambda do |notification|
    # Handle notification here...
  end)

The enumerateObjectsWithOptions:usingBlock: method of NSArray presents a more complicated case of a C block, which accepts 3 arguments: the enumerated object, its index position in the array and a pointer to a boolean variable that can be set to true to stop the enumeration.

- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts
        usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;

Assuming we want to stop at the 10th iteration:

ary.enumerateObjectsWithOptions(options, usingBlock:lambda do |obj, idx, stop_ptr|
  stop_ptr[0] = true if idx == 9
end)

(Obviously this example is used for educational purposes, in RubyMotion there is no need to use this method, because NSArray responds to the Ruby Array interface which is much more elaborate.)

Important The Proc object must have the same number of arguments as the C function pointer or block, otherwise an exception will be raised at runtime.
Important In case of a C function pointer argument, you need to make sure the Proc object will not be prematurely collected. If the method will call the function pointer asynchronously, a reference to the Proc object must then be kept. Memory management is discussed in the following section.

1.4. Memory Management

RubyMotion provides automatic memory management; you do not need to reclaim unused objects.

Since memory can be limited on iOS hardware, you must take care not to create large object graphs.

RubyMotion implements a form of garbage collection called reference counting. An object has an initial reference count of zero, is incremented when a reference to it is created and decremented when a reference is destroyed. When the count reaches zero, the object’s memory is reclaimed by the collector.

RubyMotion’s memory management system is designed to simplify the development process. Unlike traditional Objective-C programming, object references are automatically created and destroyed by the system. It is very similar to Objective-C’s ARC, in design, but it is implemented differently.

Note Object collections are triggered by the system and are not deterministic. RubyMotion is based on the existing autorelease pool infrastructure. The system creates and destroys autorelease pools for you, for instance, within the event run loop.

1.4.1. Weak References

Object cycles, when two or more objects refer to each other, are currently not handled by the runtime. It is therefore important to explicitly create weak references in this case, to avoid the referred objects to leak memory.

RubyMotion implements the WeakRef class, similar to the one in the Ruby’s weak_ref standard library. Weak references can be created using WeakRef.new(obj), and the passed object will not be retained. All messages sent to the WeakRef object will be forwarded at the dispatcher level to the passed object.

Here is an example implementing the delegate pattern using a weak reference.

class MyView
  def initialize(delegate)
    @delegate = WeakRef.new(delegate)
  end

  def do_something
    # ...
    @delegate.did_something
  end
end

class MyController
  def initialize
    @view = MyView.new(self)
  end

  def did_something
    # ...
  end
end

Without a weak reference here, both MyView and MyController objects would leak memory.

Note We expect the RubyMotion runtime to be able to deal with cyclic references at some point. Once it happens, the WeakRef class will be replaced with a no-operation.

1.4.2. Objective-C and CoreFoundation Objects

Objects created by Objective-C or CoreFoundation-style APIs are automatically managed by RubyMotion. There is no need to send the retain, release or autorelease messages to them, or use the CFRetain or CFRelease functions.

The following piece of code allocates two NSDate objects using different constructions. In typical Objective-C, the returned objects would need to be differently managed. In RubyMotion both objects will be entitled to garbage-collection.

date1 = NSDate.alloc.init
date2 = NSDate.date

In order to prevent an object from being collected, a reference must be created to it, such as setting an instance variable to it. This will make sure the object will be kept alive as long as the instance variable receiver is alive.

@date = date1   # date1 will not be collected until the instance variable receiver is collected

There are other ways of creating references to an object, like setting a constant, using a class variable, adding the object to a container (such as Array or Hash) and more. Objects created in RubyMotion and passed to Objective-C APIs will also be properly referenced if needed.

1.4.3. Immediate Types

The Fixnum and Float types in RubyMotion are immediates; they don’t use memory resources to be created. The runtime uses a technique called tagged pointers to implement this.

The ability to use these types without affecting the memory usage is important as a sizable part of a real-world app is spent in control drawing, which can make intensive use of arithmetic algorithms.

Note Since iOS is using a 32-bit architecture, immediate types are encoded on a 30-bit pointer (we need 2 bits for type information). On OS X, immediate types will be encoded on a 62-bit pointer when the program runs on recent Mac computers, which are powered by a 64-bit architecture.

1.5. Concurrency

The ability to run code concurrently became critical as multicore processors appeared on iOS devices. RubyMotion has been designed around this purpose.

RubyMotion has the concept of virtual machine objects, which wrap the state of a thread of execution. A piece of code is running through a virtual machine.

Virtual machines don’t have locks and there can be multiple virtual machines running at the same time, concurrently.

Caution Unlike the mainstream Ruby implementation, race conditions are possible in RubyMotion, since there is no Global Interpreter Lock (GIL) to prohibit threads from running concurrently. You must be careful to secure concurrent access to shared resources.

Different options are available to write concurrent code in RubyMotion.

1.5.1. Threads and Mutexes

The Thread class spawns a new POSIX thread that will run concurrently with other threads. The Mutex class wraps a POSIX mutex and can be used to isolate concurrent access to a shared resource.

1.5.2. Grand Central Dispatch

RubyMotion wraps the Grand Central Dispatch (GCD) concurrency library under the Dispatch module. It is possible to execute both synchronously and asynchronously blocks of code under concurrent or serial queues.

Albeit more complicated to comprehend than regular threads, sometimes GCD offers a more elegant way to run code concurrently. GCD maintains for you a pool of threads and its APIs are architectured to avoid the need to use mutexes.

2. Android

From this part of the document we will refer to the RubyMotion runtime as the one that powers Android RubyMotion projects.

Note Android support is currently in public beta. While it is fully functional, we are still working on making it ready for prime time.

2.1. Object Model

The RubyMotion object model is based on Java, the de-facto programming language of Android, Google’s mobile platform.

More specifically, RubyMotion re-implements the Ruby language on top of the Java Native Interface (JNI) of the Android runtime.

While Java has certainly less similarities with Ruby than Objective-C, they are still close enough to make such an integration possible.

In RubyMotion, all objects are Java objects, all Java classes and methods are available in Ruby, and some Ruby classes and methods are available to Java. This unified approach allows us to interface with the native Java APIs at no extra performance cost.

RubyMotion is compatible with both Dalvik and ART Android runtimes.

2.1.1. Classes

All Java classes are natively exposed to Ruby. However, the way to access them differs from the syntax you would use in Java.

Java features the notion of packages, which is a way to group a set of classes under a component that can be either accessed directly or included.

As an example, java.lang.Object represents a path where the Object class is defined under the java.lang package. Java classes are often described using their full package path.

In RubyMotion, Java packages are accessed as if they were defined as a chain of Ruby constants, where each part of the package starts with an upper-case character.

In Ruby, the java.lang.Object path can be accessed using Java::Lang::Object.

obj = Java::Lang::Object.new

Java classes which are not defined as final can be subclassed. As an example, the public non-final android.app.Activity class is available as Android::App::Activity in Ruby, and can be subclasses as following.

class MyActivity < Android::App::Activity
  # ...
end
Note At the time of this writing, packages cannot be included in Ruby, so you have to use full paths.

2.1.2. Primitive Java Types

Like Objective-C, Java comes with a set of primitive / builtin data types. Java methods make use of these types, and it is important to describe how they are interfaced with Ruby code.

Java Type From Ruby to Java From Java to Ruby

boolean

If the object is false or nil, false, otherwise, true. Note: the 0 fixnum will evaluate to true.

Either true or false.

byte

If the object is a Fixnum or a Bignum, the value is returned. If the object is true or false, 1 or 0 are respectively returned. If the object responds to the to_i message, it is sent and the result is returned.

Either a Fixnum or a Bignum object.

char

short

int

long

float

If the object is a Float, the value is returned. If the object is true or false, 1.0 or 0.0 are respectively returned. If the object responds to the to_f message, it is sent and the result is returned.

A Float object.

double

2.1.3. Builtin Ruby Classes

Some of the built-in classes of RubyMotion are based on the Java Class Library, the core classes of the Android SDK.

Java comes with a class called java.lang.Object, which is the root class of all Java classes.

Because of RubyMotion’s unified runtime approach, all Ruby classes are also based on java.lang.Object. The Object constant point to that class as well.

Here is a table showing the base class of a newly created class, Hello, as well as some of the Ruby built-in classes.

Ruby Class Base

Hello

java.lang.Object

Fixnum

java.lang.Integer

Float

java.lang.Float

Proc

java.lang.Runnable (interface)

String

java.lang.CharSequence (interface)

Array

java.util.ArrayList

Hash

java.util.HashMap

Thread

java.lang.Thread

Regexp

java.util.regex.Pattern

MatchData

java.util.regex.Matcher

The main purpose of this design is to allow the exchange of primitive types between Java and Ruby at no performance cost, since they don’t have to be converted. This is important as most of the types that will be exchanged in a typical application are likely going to be built-in types.

A String object created in Ruby can have its object reference passed as the argument of an Java method that expects an object that implements the java.lang.CharSequence interface, such as the setText method of android.widget.TextView class.

textView.text = "foo"

2.1.4. Methods

Java methods are natively exposed to Ruby, and can be accessed as if they have been defined as Ruby methods.

As an example, the java.lang.Object class implements the toString() method.

String  toString()

That method can be called on all objects in Ruby.

42.toString         #=> "42"
true.toString       #=> "true"
textView.toString   #=> "android.widget.TextView{3607..."

When you are subclassing a Java class in Ruby, you can override any of its methods.

As an example, the android.app.Activity class implements the onCreate() method, which is meant to be overridden by subclasses.

void onCreate (Bundle savedInstanceState)

We can do that naturally from Ruby.

class MyActivity < Android::App::Activity
  def onCreate(saved_instance)
    super
    # ...
  end
end

Note that we use the super Ruby language keyword to call the super class implementation, defined in Java.

2.1.5. Method Shortcuts

The RubyMotion runtime provides convenience shortcuts for certain Java methods.

Method Shortcut

setFoo

foo=

getFoo

foo

As an example, the getText and setText methods of android.widget.TextView can be called using the text and text= shortcuts.

view.text          # instead of view.getText
view.text = "foo"  # instead of view.setText("foo")

2.1.6. Interfaces

Java interfaces are an important concept to understand when programming Android apps with RubyMotion.

In Java, an interface is basically a list of method declarations. A class is said to implement an interface when it provides definitions for all the methods in the interface.

Note Java interfaces are similar to protocols in Objective-C.

In RubyMotion, you can implement an interface in a class just by defining the required methods. There is no need to specify the name of the interface, the compiler will determine that for you automatically.

As an example, the setOnClickListener method of android.view.View expects an object that implements the android.view.View.OnClickListener interface, which features only one method, onClick.

abstract void   onClick(View v)

In order to implement that interface in Ruby, you just need to provide an implementation for that method in a class.

class MyButtonListener
  def onClick(view)
    # ...
  end
end

# ...
button.onClickListener = MyButtonListener.new

2.1.7. Methods Overloading

Java features the concept of method overloading, which does not exist in Ruby.

In Java, it is possible to define the same method name multiple times but with different argument types. The compiler will then identify which method has to be called.

As an example, the android.widget.TextView Java class features the following setText methods:

void    setText(int resid)
void    setText(char[] text, int start, int len)
void    setText(int resid, TextView.BufferType type)
void    setText(CharSequence text)
void    setText(CharSequence text, TextView.BufferType type)

As you can see, each of these methods have the same name (and return type) but have different arguments.

Because Ruby is dynamically-typed, overloaded methods have to be resolved at runtime and not at compile time.

The setText(int resid) method will be called if you pass a Fixnum to it. The setText(CharSequence text) method will be called if you provide an object that implements the CharSequence interface (such as a string).

textView.text = 42      #=> calls setText(int)
textView.text = 'foo'   #=> calls setText(CharSequence)

In case the runtime cannot figure out which overloaded method to call during a method dispatch, a NoMethodError exception will be raised with an appropriate message.

2.1.8. Fields

Java fields are variables attached to a class. There are two types of Java fields:

  1. Instance fields; these are similar to instance variables in Ruby.

  2. Static fields; these are similar to class variables in Ruby.

In the Android SDK, constants are usually static Java fields, and can be retrieved exactly as if they were constants in Ruby.

For example, the android/widget/LinearLayout class has a few constants.

public static final int HORIZONTAL
public static final int VERTICAL
...

These constants can be naturally retrieved in Ruby.

layout = Android::Widget::LinearLayout.new(self)
layout.orientation = Android::Widget::LinearLayout::VERTICAL

Instance Java fields can be retrieved in Ruby as if they were defined using attr_accessor.

2.1.9. Annotations

Java annotations are special objects that can be applied to methods (and other types).

An example is the WebKit framework of Android, which requires methods to be exposed to JavaScript to be properly annotated, for security reasons.

This can be done in RubyMotion using the annotation special method right before the definition of a method. The annotation will be retrieved at compilation time.

class DemoJavaScriptInterface
  __annotation__('@android.webkit.JavascriptInterface')
  def methodFromJavaScript
  end
end
Note At the time of this writing, only methods can be annotated in RubyMotion.

2.2. Memory Management

RubyMotion relies on the Dalvik or ART garbage collector to allocate and dispose of unused memory.

From a Ruby developer perspective, you do not have to think about memory management at all.

Internally, RubyMotion makes use of local references for local variables and global references for everything else. The destruction of local references is determined at compilation time.

There are two important things you might need to consider:

  1. The garbage collector is multithreaded. Collections might happen on other threads. If you override the finalize method of java.lang.Object in your code, make sure it’s properly re-entrant.

  2. The garbage collector is able to detect and handle cyclic references. Unlike RubyMotion for iOS and OS X, you do not need to create WeakRef objects.

2.3. Concurrency

RubyMotion has been designed for concurrency in mind.

RubyMotion has the concept of virtual machine objects, which wrap the state of a thread of execution. A piece of code is running through a virtual machine.

Virtual machines don’t have locks and there can be multiple virtual machines running at the same time, concurrently.

Caution Unlike the mainstream Ruby implementation, race conditions are possible in RubyMotion, since there is no Global Interpreter Lock (GIL) to prohibit threads from running concurrently. You must be careful to secure concurrent access to shared resources.

The Thread class is available for concurrency patterns. It is a direct subclass of java.lang.Thread.