RubyMotion Success Story: QuickLens
Pavan Podila started QuickLens to be a handy tool while doing screencasts. It has evolved to be a lot more than just that! QuickLens is a powerful Mac App for UI Designers/Developers. It floats on top of all windows and comes with a suite of tools to magnify areas, sample colors, measure dimensions, check alignments and much more. After some initial feedback from designer and developer friends, Pavan incorporated many more features, driven purely by need.
What kind of programming were you doing when you started using RubyMotion?
I have been a Front-end developer for 10 years now, starting with Java, then .Net and now focusing purely on Web, iOS and Mac. Over the years, I have also developed good taste in design, so these days I see myself as a Designer/Developer hybrid.
How did you get started on QuickLens and RubyMotion?
Before RubyMotion announced support for OS X in their 2.0 version, I was coding away in MacRuby and Objective-C. Although MacRuby was great for prototyping, it was lacking the maturity and polish of RubyMotion. When 2.0 came out, it totally changed my world. I immediately jumped on it and was able to build the first version of my app within 3 days! In fact I even tweeted about it at that time.
The ride on the RubyMotion train wasn't always scenic. I had a few memory related issues, API incompatibility with frameworks like Carbon and the occassional regression. But thanks to the fantastic support, all of these were fixed very quickly. Overall I have been very happy with the productivity. Frankly, without RubyMotion, I would have taken much longer to ship 1.0 of QuickLens.
Speaking of support, what did you do when you ran into issues with the compiler?
This has happened a few times, especially early on when RubyMotion just announced support for OS X. I had issues with certain function signatures (esp. those involving blocks) or some weird crash in Cocoa/Carbon API, which was hard to debug. Most often I would hit up
motion supportand file a ticket. Eloy, Joffrey or Shizuo would generally respond within a day and sometimes file a separate ticket on YouTrack. Sometimes even Laurent would chip in with some work arounds. I also had some trouble with the
Pointerclass when using with some Carbon API. For example, here is a snippet that took me several days to figure out, with lots of help from Laurent!
This snippet is part of the Carbon API that reads the default keyboard layout. I use it in my custom control for recording Global Hotkeys.
currentKeyboard = TISCopyCurrentKeyboardInputSource() layoutDataPtr = TISGetInputSourceProperty(currentKeyboard, KTISPropertyUnicodeKeyLayoutData) keyboardLayout = layoutDataPtr.to_object.bytes.cast!(UCKeyboardLayout.type)
layoutDataPtris an instance of
Pointer. The last line where I apply a chain of methods was quite hard to figure out!
What is it about RubyMotion that makes you feel so productive?
I think its a combination of the command line tools, REPL, the Ruby language and the awesome and vibrant community. I have learnt a lot from the experiences and code shared by folks. Reading the code of libraries such as: Bubblewrap, Promotion, Sugarcube, RubyMotionQuery and many others has been quite illuminating. It has given me enough impetus to structure my own code. I sure want to contribute back in my own little way, hopefully by open-sourcing some of the reusable parts of my app.
I should also mention that the Apple frameworks, especially AppKit, Cocoa, Quartz, QuartzCore are very well designed. With the Ruby language, they become more approachable and easier to use.
What features in Cocoa or Xcode did you feel were difficult in RubyMotion?
As I mentioned earlier, it was the early battles with block based Cocoa APIs and some Carbon APIs. A particular block-based Cocoa API which troubled me was:
panel = NSOpenPanel.openPanel panel.beginSheetModalForWindow window, completionHandler: ->(result) do end
The first time it was a compiler issue not identifying the block signature properly. Then it was fixed in the next RM release and then there was a regression and finally fixed in a later release. It was an interesting roller-coaster ride with that API :-)
Using Interface Builder for designing some of the views and windows was also a bit of challenge. In the end I created an empty XCode project with all the xibs and a simple
Stub.hfile that had the interfaces for all the Views, Controls, ViewControllers and Windows. Luckily IB picks up changes to the
Stub.hin real-time, so the workflow is not that bad.
Are there any tools that you recommend to new RubyMotion developers?
I have personally used the JetBrains RubyMine IDE with great success, so that is definitely recommended. Other than that, I would encourage learning some Objective-C as well, which will help when converting some APIs into Ruby. Once you get comfortable with the RubyMotion toolset, it really comes down to understanding the AppKit, Cocoa and other framework APIs. I have really spent a disproportionate amount of time in the Cocoa and Quartz API docs for this app. RubyMotion is really fun once you get a good grip over the Apple Frameworks! Know Thy API.
Instruments is one other tool that every developer should know well. Effective use of Instruments is the key to identifying and fixing memory leaks and performance issues.
Now that you've built the entire app using RubyMotion, would you choose to use it again if you had to start over?
In light of the recent WWDC announcements, it may seem that Swift is a natural choice for new apps. Although the syntax and features are great, it is still very new and has lots of issues with Cocoa APIs. I did some of my own experiments and found it very tedious with all the type-casts for Cocoa/Quartz APIs. That coupled with the crashes and poor editor support in XCode really makes it a frustrating experience. I am sure Apple will improve this over time but as of now, it is pretty bad. Actually it seems worse in contrast to the experience I've had with RubyMotion and RubyMine IDE.
Additionally from a language point of view, Ruby seems more suited for UI development than Swift. Add in some meta-programming ideas, and you have a powerful system in your hands.