3. Bridge Notes
3.1 Calling conventions: calling Objective-C from Ruby
RubyObjC uses a simple convention to call Objective-C methods from Ruby. Colons (:) in selector names are replaced with underscores (_), and all parts of the selector are concatenated to form the Ruby method name.
For example, to call the makeObjectsPerformSelector:withObject: method of NSArray, you would write Ruby code that looked like this:
myArray.makeObjectsPerformSelector_withObject_("danceWith:", me)
Here we assume that myArray is an NSArray containing objects that are able to respond to the “danceWith:” selector, and that me is an acceptable argument value to send with the selector.
3.2 Calling conventions: calling Ruby from Objective-C
When they are properly declared, Ruby methods are easy to call from Objective-C. In fact, the Objective-C code probably won’t be any different from code that callse Objective-C methods. To the Objective-C caller, RubyObjC methods look exactly like methods written in Objective-C.
For a Ruby method to be available from Objective-C, it must first be a method of a class in the hierarchy rooted at ObjC::Object. Usually this means that its Ruby class is derived from ObjC::NSObject or the wrapper for a Cocoa class derived from NSObject, such as ObjC::NSWindowController.
Ruby methods can be added to Objective-C classes either as instance methods or as class methods.
Adding Instance Methods to Objective-C classes from Ruby
To add a Ruby method as an instance method, declare it with the imethod declarator. For example, the following adds a simple instance method to an application delegate class:
class ApplicationDelegate < ObjC::NSObject imethod "applicationDidFinishLaunching:", "v@:@" do |sender| ... end end
In this case, the applicationDidFinishLaunching: method is not known to the Objective-C runtime, but because it resembles an action, its signature will be assumed to be “v@:@” and could be safely omitted. There’s more on this below.
Adding Class Methods to Objective-C classes from Ruby
To add a Ruby method as a class method, declare it with the cmethod declarator. For example, the following adds an initialize method to an application delegate class:
class ApplicationDelegate < ObjC::NSObject cmethod "initialize", "v@:" do .... end end
In this case, the “initialize” method is known to the Objective-C runtime and its signature could be safely omitted.
In general, when a method signature is not specified in an imethod or cmethod declaration, RubyObjC will look in the Objective-C runtime for a method with the same name as the method being declared. If one exists, its signature is used. If no such method exists, the bridge has two fallbacks:
1. If the method name looks like an action (a single word ending in ’:’ ), then it is given a default signature of v@:@.
2. If the method name looks like an accessor (a single word containing no ’:’), then it is given a default signature of @@:.
To get the signature to use with a method, concatenate the type codes for its return type and arguments. The return type is first, then there are codes for two hidden arguments, the message receiver ’@’ and the selector being sent ’:’. That’s followed by the codes for each argument.
You can refer to Apple’s Developer Connection web site for a description of the individual type codes.
You can also use RubyObjC to check the signature of any method in the Objective-C runtime. For details, see the next section.
Looking deeper
To easily see whether a method is known to the Objective-C runtime, use the ObjC.get_methods function to get a Ruby hash containing all known methods, indexed by the method name. For exampleirb(main):001:0> m = ObjC.get_methods ... irb(main):002:0> m["initialize"] => initialize irb(main):003:0> m["initialize"].signature => "v@:"Be careful, though, sometimes multiple methods exist with the same name and different signatures. When this is the case, the get_methods function currently returns only one such method, which is the one that would be used to automatically determine the signature of methods added without explicitly-specified signatures. When there’s doubt, it’s best to explicitly specify a signature.
RubyObjC also provides ways for you to get to the methods associated with specific classes. Here’s one example:
irb(main):007:0> ObjC::NSImageView.imethods.select {|m|
irb(main):008:1* m.name == "imageAlignment"}[0].signature
=> "i@:"
For more details, see the online documentation for
ObjC::Object,
ObjC::Class, and
ObjC::Method.
3.3 Working with Objective-C objects from Ruby
irb(main):001:0> ObjC::NSObject.new
NoMethodError: undefined method `new' for ObjC::NSObject:Class
from (irb):2
Did you find an error? Is something missing? Post your comment or suggestion below!
Comments (0) post