During our trip in Tokyo last month, I and my wife attended TOKYO Rails #19 at COOKPAD, and that is fantastic.
While I don’t actually coding Rails lately, I’m lucky to met a few iOS developers and exchanged a bit, such as introducing もじバトル, SplitCam and EverClip, and see some interesting in house app as well as a creative camera app Cobypic.
And oh, the event venue COOKPAD office is super cool. Their guys kindly made us a fantastic meal. Sorry that I can only bring you a few pictures:
I can’t made it to their iOS meetup… maybe next time!
When using RubyMotion, just like many other new technologies or frameworks, I found gotchas and scratch my head over them.
I’m writing them down in case I might forget them. I hope this may help you or give you ideas on daily issues you might face when using RubyMotion.
When class is not class
Try to convert following Objective-C code into RubyMotion code:
That is wired, but it is not that wired if we think again.
In Objective-C, there is a “+class” class method in NSObject. As its name suggested, it return the class object of the specifing class. For example, [UIView class] return UIView class object.
In Ruby, there is a “#class” instance method in Object. When you called this on an instance of object, it return the class of that object. For example, my_view.class return UIView if my_view is an instance of UIView. Note there are no class method “::class” on Object on Ruby. Why you can still call something like “Time.class” in ruby? It is because any class in Ruby is actually instance of Class.
This explain why MyCell.class in RubyMotion is different from [MyCell class] in Objective-C. Instead of returning class “MyCell”, MyCell.class returning the class of MyCell class.
Both way correctly pass the class “MyCell” to the registerClass:forCellWithReuseIdentifier: method.
When nil is not NULL
In Objective-C (inherited from C), NULL is macro point to null-pointer constant. It is a special value that indicates that the pointer is not pointing to any object.
NULL is a value, and you cannot adds value to Objective-C collection. Therefore they created null object [NSNull null] to represent “nothing” in collection.
In Ruby, nil is a singleton object which represent “nothing”. Naturally RubyMotion inherited this. To make it simple to work on Objective-C collection, [NSNull null] returns nil.
The problem is while Ruby API only recognize nil, various Cocoa API use NULL as a special value. In RubyMotion, there are no way you could specify NULL value.
Remember nil is NOT NULL. When using RubyMotion, you must aware that you have NO way to specify NULL, and be prepared to workaround Cocoa API that expects NULL.
My new app use msgpack to encode data before sending to server. On server side,
its a Sinatra app that decode and store the data to database.
The app works fine until I push real data. With real data the app crash with error
“invalid byte sequence in UTF-8”.
After some lengthy investigation, I found the data I sent to server is decoded
incorrectly. The offending code look like this:
1
unpacked=MessagePack.unpack(data)
What could possibly gone wrong?
Turns out as discussed here,
msgpack is a binary serialization format, and it expects to unpack from a raw binary string. You
need to force the data string (from HTTP POST request) to binary encoding.
P.S. If you use JRuby and msgpack-jruby, beware another issue that, msgpack-jruby
behave differently than the MRI version. It will not use default_external
encoding, but you will need to explicitly specify the encoding during unpack. (As
discussed here)
Want to profile or analyze your RubyMotion application? How to use Instrument with motion
is not yet known, but you can always use powerful DTrace to do that.
Turns out running DTrace in RubyMotion is exactly same as that in MacRuby (no surprise!).
motion-dtrace is a proof of concept to simplify
running dtrace with your app.
Installation
1
gem install motion-dtrace
Usage
Edit the Rakefile of your RubyMotion project and add the following require line.
12
require 'rubygems'
require 'motion-dtrace'
Start simulator process:
1
rake
On another terminal, start dtrace:
1
rake dtrace
When you terminate the app, you get a trace similar to following:
To add a gem to your RubyMotion project, instead of using rubygems to require source files in runtime, you
require it in project Rakefile.
Inside the source file being required, instead of require other files normally you would in rubygems, use
Motion::Project::App.setup to add sources to your motion project:
123456789
unlessdefined?(Motion::Project::Config)raise"This file must be required within a RubyMotion project Rakefile."endMotion::Project::App.setupdo|app|Dir.glob(File.join(File.dirname(__FILE__),'nano_store/*.rb')).eachdo|file|app.files.unshift(file)endend
If the project already using cocoapods, above code will just work. If you have not include
any other pods in the project, add following lines to the project Rakefile:
12345678
Motion::Project::App.setupdo|app|app.name='myapp'# Only needed if you have not already specifying a pods dependencyapp.podsdodependency'NanoStore','~> 2.0.1'endend
Conclusion
Now you are ready to roll. Have a look of following RubyMotion gems if you need more help:
These few days I have been playing with RubyMotion.
They have documents on using Objective-C libraries. So using familiar library such as TouchJSON is not an issue.
How about using Ruby library such as BubbleWrap? There are no documents on how to include and write gems in your project yet. Before it is ready, you can do this: