You are on page 1of 30

RubyMotion Cookbook

RubyMotion is a commercial iOS development platform using ruby, which adheres to apple appstore specification it is built by Laurent Sansonetti . In RubyMotion Cookbook I will present solutions for common tasks for building iOS apps, this is based on code published on open source projects, tutorials, porting native apps to RubyMotion. You can post your questions / problems / suggestions / sample code / corrections on this link given below I would try to get a solution and also add it to this book and the accompanying code. Every contribution would be attributed. https://github.com/railsfactory/rubymotion-cookbook/issues

RubyMotion Cookbook

Installation
I am assuming you already have a mac with OSX Lion and App Store installed. Open the app store, search for xcode, click on it, it is a free app , download it.

Xcode Install
This is a huge file about 1.5GB, so you need to a good connection and have enough time to download in a single stretch. Make sure you have couple of GB's of free space. Xcode gets installed in /Developer in your hard disk/SSD. For running the app built by you on device you would need a Apple developer account, I would add the instructions at a later time.

RubyMotion install
Ruby comes preinstalled in OSX Lion, open terminal and check the version.
$ ruby -v ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]

If you are a advanced user you can get RVM and install a custom ruby version. Goto RubyMotion site and click on the buy link and buy your RubyMotion License. Rates as on 9th May is 149$ it is a early bird rate so hurry. Download the installer http://www.rubymotion.com/files/RubyMotion%20Installer.zip . Please have your license code ready as it asks at this stage. Open the zip file and run the installer. Accept the terms and conditions, enter the license key and begin install, you would be prompted for your system password, once that is done in couple of seconds the install would complete and you are ready to work with RubyMotion.

Installation

Getting Started
Your Mac is ready to run RubyMotion, but it is a good idea to view initial screencasts which make understand the concepts in a visual way

Official intro screencast


(http://www.youtube.com/user/hipbyte)[http://www.youtube.com/user/hipbyte] on this Youtube channel you can find 2 interesting videos and hope there would be more videos published in coming days. RubyMotion: Introduction Video 8:51 RubyMotion: Interactive Console Demo 1:09 Interctive Console/REPL is the killer feature which makes it worth diving into RubyMotion.

Pragmatic Studios screencast


http://pragmaticstudio.com/screencasts/rubymotion 50:25 This is a longer version and shows a full cycle of building a app from scratch, self explanatory.

Forum
this is the place to go and find solutions for your problems, RubyMotion Google Group Most participants are early adopters, just like you and good discussions happen, please be polite and somebody would try to help you resolve your issues. Bonus, You can make feature requests as well. Just remember this is a closed/moderated group.

Getting Started

Build your first app


after seeing the screencasts you would be charged up, now let us begin

Motion command
let us run motion and know what this command can do
$ motion Usage: motion [-h, --help] motion [-v, --version] motion <command> [<args...>] Commands: create activate update support

Create a new project Activate the software license Update the software Create a support ticket

Update motion command


RubyMotion is a moving target and it is getting frequent release, I have personally updated from 1.0 to 1.1 , 1.2, 1.3 in less than a week. one thing for sure, Laurent Sansonetti, the RubyMotion author listens to customer feedback and bug reports and fixes at a astonishing pace. I have tested over 40 apps and crashes have reduced by over 90% between these updates.
$ sudo motion update $ motion -v 1.3

Hello World
It is obligatory to build a Hello World app in every technology/language
$ motion create hello Create hello Create hello/.gitignore Create hello/Rakefile Create hello/app Create hello/app/app_delegate.rb Create hello/resources Create hello/spec Create hello/spec/main_spec.rb

Our project is created and at this stage we can run it on our iOS simulator
$ cd hello $ rake Build Compile Create Link Create Create Create Simulate

./build/iPhoneSimulator-5.0-Development ./app/app_delegate.rb ./build/iPhoneSimulator-5.0-Development/hello.app ./build/iPhoneSimulator-5.0-Development/hello.app/hello ./build/iPhoneSimulator-5.0-Development/hello.app/Info.plist ./build/iPhoneSimulator-5.0-Development/hello.app/PkgInfo ./build/iPhoneSimulator-5.0-Development/hello.dSYM ./build/iPhoneSimulator-5.0-Development/hello.app

Build your first app

2012-05-10 23:54:08.743 hello[29464:f803] Applications are expected to have a root view controller at the end of appl (main)>>

Just ran one command and voila the iOS Simulator is running in iPhone mode and a blank screen is running. Actually your application was compiled, copied to the simulator and executed on the simulator.

Exiting the app


There are three ways Command + Q when the iOS simulator app is selected and simulator quits, easiest but not intuitive, the app running terminal would break abruptly. Not a nice way for a programmer. ((null))>> $ Ctrl+c interrupts the program immediately.Not a nice way for a programmer. (main)>> rake aborted! Command failed with status (1): [ /Library/RubyMotion/bin/sim 2 1 5.0 "/Dev...] Tasks: TOP => default => simulator (See full trace by running task with --trace) $ from the terminal type 'exit' (main)>> exit $ Third way is the recommended version but when app hangs or crashes or erratic behavior you know now how to get out of it.

How it works
now you know the code works, what code boilerplate has been added WIP

Build your first app

Let there be Hello World


Let us add some text and display it, one of the simplest to display message is Label or a alert Message, I dont want to create additional files or config, let us do it in a ruby way, from the RubyMotion console(REPL)
$ rake Build ./build/iPhoneSimulator-5.0-Development Simulate ./build/iPhoneSimulator-5.0-Development/hello.app 2012-05-12 08:43:50.545 hello[46454:f803] Applications are expected to (main)>> hello = UIAlertView.new => #<UIAlertView:0x8dac150> (main)>> hello.message = "Hello World" => "Hello World" (main)>> hello.show => #<UIAlertView:0x8dac150>

have a root view controller at the end of

Did you see the message is now displayed on your simulator. Can we change the message to something else, easy
(main)>> hello.message = "Thanks Laurent and Matz" => "Thanks Laurent and Matz"

What else can I do

=> hello.methods => [:"addTextFieldWithValue:label:", :titleLabel, :canBecomeFirstResponder, :numberOfRows, :table, :keyboard, :textField, :"setSubtitle:", :subtitle, :tableView, :dismiss, :"initWithTitle:buttons:defaultButtonIndex:delegate:context:", :"setNumberOfRows:", :"popupAlertAnimated:", :"setDimView:", :"setTitleMaxLineCount:", :"setRunsModal:", :"setBodyText:", :"setAlertSheetStyle:", :"buttonAtIndex:", :requiresPortraitOrientation, :textFieldCount, :buttons, :"layoutAnimated:", :"dismissAnimated:", :"popupAlertAnimated:atOffset:", :"presentSheetFromAboveView:", :"presentSheetFromBehindView:", :groupsTextFields, :"setGroupsTextFields:", :"setTaglineText:", :bodyText, :titleMaxLineCount, :"setBodyTextMaxLineCount:", :bodyMaxLineCount, :"setDefaultButton:", :defaultButton, :"setDestructiveButton:", :destructiveButton, :"addButtonWithTitle:label:", :"addButtonWithTitle:buttonClass:", :buttonCount, :"setTableShouldShowMinimumContent:", :tableShouldShowMinimumContent, :"setShowsOverSpringBoardAlerts:", :showsOverSpringBoardAlerts, :isBodyTextTruncated, :"presentSheetInView:", :"presentSheetToAboveView:", :backgroundSize, :alertSheetStyle, :"setDimsBackground:", :dimsBackground, :"setSuspendTag:", :suspendTag, :"setBlocksInteraction:", :blocksInteraction, :runsModal, :titleRect, :numberOfLinesInTitle, :"presentSheetFromButtonBar:", :"replaceAlert:", :"popupAlertAnimated:animationType:atOffset:", :"popupAlertAnimated:animationType:", :"setKeyboardShowsOnPopup:", :bodyTextLabel, :taglineTextLabel, :"setForc :forceHorizontalButtonsLayout, :resignFirstResponder, :becomeFirstResponder, :layout, :context, :"setContext:", :"initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles:", :"showWithAnimationType:", :show, :cancelButtonIndex, :"dismissWithClickedButtonIndex:animated:", :isVisible, :"addButtonWithTitle:", :"setCancelButtonIndex:", :numberOfButtons, :"buttonTitleAtIndex:", :"textFieldAtIndex:", :"setMessage:", :"setDefaultButtonIndex:", :"initWithTitle:message:delegate:defaultButton:cancelButton:otherButtons:", :defaultButtonIndex, :firstOtherButtonIndex, :"setAlertViewStyle:", :alertViewStyle, :dealloc, :"initWithFrame:", :"setTitle:", :title, :"setDelegate:", :delegate, :message, :"resizeForKeyplaneSize:",

Let there be Hello World

:"drawRect:forViewPrintFormatter:", :viewPrintFormatter, :textInputView, :isAccessibilityElementByDefault, :isElementAccessibilityExposedToInterfaceBuilder, :textEffectsVisibilityLevel, :textEffectsVisibilityLevelWhenKey, :"compareTextEffectsOrdering:", :needsWebDocumentViewEventsDirectly, :"reduceWidth:", :"gestureEnded:", :"setGestureDelegate:", :"setEnabledGestures:", :"setValue:forGestureAttribute:", :"gestureStarted:", :"gestureChanged:", :"stateForGestureType:", :"animator:stopAnimation:", :"animator:startAnimation:", :"zoomToScale:", :"rotateToDegrees:", :canHandleGestures, :gestureDelegate, :enabledGestures, :"valueForGestureAttribute:", :"setRotationDegrees:duration:", :rotationDegrees, :"endEditing:", :useBlockyMagnificationInClassic, :scriptingInfoWithChildren, :recursiveDescription, :description, :"layoutSublayersOfLayer:", :"actionForLayer:forKey:", :"drawLayer:inContext:", :"setValue:forKey:", :gestureRecognizers, :removeAllGestureRecognizers, :"removeGestureRecognizer:", :"setGestureRecognizers:", :gesturesEnabled, :"setGesturesEnabled:", :deliversTouchesForGesturesToSuperview, :"setDeliversTouchesForGesturesToSuperview:", :"addGestureRecognizer:", :viewTraversalMark, :isInAnimatedVCTransition, :"setInAnimatedVCTransition:", :"setViewTraversalMark:", :skipsSubviewEnumeration, :"setSkipsSubviewEnumeration:", :frameOrigin, :"setFrameOrigin:", :"pointInside:forEvent:", :"hitTest:forEvent:", :"initWithSize:", :"setClipsSubviews:", :"createSnapshotWithRect:", :"setEnabled:", :isEnabled, :"setSize:", :size, :"addAnimation:forKey:", :"setNeedsDisplayOnBoundsChange:", :"setAlpha:", :"setContentScaleFactor:", :"setClearsContextBeforeDrawing:", :"setContentMode:", :"setContentStretch:", :"setClipsToBounds:", :clearsContextBeforeDrawing, :contentMode, :contentStretch, :clipsToBounds, :contentScaleFactor, :"setClearsContext:", :recursivelyForceDisplayIfNeeded, :visibleBounds, :"setFixedBackgroundPattern:", :isHiddenOrHasHiddenAncestor, :"setContentsPosition:", :"newSnapshotWithRect:", :forceDisplayIfNeeded, :alpha, :needsDisplay, :needsDisplayOnBoundsChange, :"setBackgroundColor:", :backgroundColor, :"setHidden:", :isHidden, :"setOpaque:", :isOpaque, :setNeedsDisplay, :"drawRect:", :"setNeedsDisplayInRect:", :didMoveToWindow, :layoutSubviews, :"sendSubviewToBack:", :"bringSubviewToFront:", :"containsView:", :layoutBelowIfNeeded, :"willMoveToWindow:", :deferredBecomeFirstResponder, :"movedFromSuperview:", :didMoveToSuperview, :"viewWithTag:", :"insertSubview:atIndex:", :"exchangeSubviewAtIndex:withSubviewAtIndex:", :"insertSubview:belowSubview:", :"insertSubview:aboveSubview:", :"didAddSubview:", :"willMoveToSuperview:", :"insertSubview:below:", :"insertSubview:above:", :"movedToSuperview:", :"viewWillMoveToSuperview:", :viewDidMoveToSuperview, :"movedFromWindow:", :"movedToWindow:", :"isDescendantOfView:", :window, :subviews, :setNeedsLayout, :superview, :removeFromSuperview, :"willRemoveSubview:", :layoutIfNeeded, :"addSubview:", :"sizeThatFits:", :"hitTest:withEvent:", :isMultipleTouchEnabled, :"resizeSubviewsWithOldSize:", :"pointInside:withEvent:", :"resizeWithOldSuperviewSize:", :autoresizingMask, :"setMultipleTouchEnabled:", :"setExclusiveTouch:", :isExclusiveTouch, :"convertSize:toView:", :"convertSize:fromView:", :hitRect, :"setFrame:forFields:", :"setRotationBy:", :"setAutoresizesSubviews:", :autoresizesSubviews, :sizeToFit, :origin, :"setOrigin:", :extent, :"setAutoresizingMask:", :"convertRect:toView:", :"convertRect:fromView:", :bounds, :transform, :position, :"setFrame:", :"setTransform:", :"setBounds:", :"convertPoint:fromView:", :"convertPoint:toView:", :frame, :center, :"setCenter:", :"setPosition:", :"setUserInteractionEnabled:", :charge, :"setTag:", :isUserInteractionEnabled, :cancelTouchTracking, :cancelMouseTracking, :tapDelegate, :"setCharge:", :"setTapDelegate:", :"startHeartbeat:inRunLoopMode:", :"stopHeartbeat:", :canHandleSwipes, :"swipe:withEvent:", :tag, :init, :layer, :nextResponder, :"initWithCoder:", :"encodeWithCoder:", :defaultFirstResponder, :nextFirstResponder, :inputAccessoryView, :inputView, :reloadInputViews, :reloadInputViewsWithoutReset, :"canPerformAction:withSender:",

Let there be Hello World

:"touchesCancelled:withEvent:", :"motionEnded:withEvent:", :"touchesBegan:withEvent:", :"touchesMoved:withEvent:", :"touchesEnded:withEvent:", :"motionBegan:withEvent:", :"motionCancelled:withEvent:", :"remoteControlReceivedWithEvent:", :"mouseDragged:", :isFirstResponder, :canResignFirstResponder, :undoManager, :"mouseDown:", :"mouseExited:", :"mouseEntered:", :"scrollWheel:", :"mouseMoved:", :"mouseUp:", :firstResponder, :sessions, :help, :quit, :"repl:", :to_plist, :"Complex:", :Complex, :"Rational:", :Rational, :"enum_for:", :enum_for, :"to_enum:", :to_enum, :object_id, :__id__, :"define_singleton_method:", :define_singleton_method, :"public_method:", :"method:", :"extend:", :extend, :"respond_to_missing?:", :"respond_to?:", :respond_to?, :"public_send:", :public_send, :"send:", :send, :"__send__:", :__send__, :"instance_exec:", :instance_exec, :"instance_eval:", :instance_eval, :__callee__, :__method__, :tap, :"is_a?:", :"kind_of?:", :"instance_of?:", :"instance_variable_defined?:", :"instance_variable_set:", :"instance_variable_get:", :instance_variables, :"public_methods:", :public_methods, :"private_methods:", :private_methods, :"protected_methods:", :protected_methods, :"singleton_methods:", :singleton_methods, :"methods:", :methods, :inspect, :to_s, :untrusted?, :untrust, :trust, :frozen?, :freeze, :untaint, :tainted?, :taint, :__type__, :dup, :clone, :"<=>:", :"eql?:", :"!~:", :"=~:", :"===:", :nil?, :"!=:", :!, :"==:", :"equal?:", :selectionAffinity, :defaultAccessibilityTraits, :"accessibilitySetIdentification:", :"indexOfAccessibilityElement:", :"accessibilityElementAtIndex:", :accessibilityElementCount, :accessibilityIncrement, :accessibilityDecrement, :"accessibilityScroll:", :accessibilityPerformEscape, :accessibilityElementDidBecomeFocused, :accessibilityElementDidLoseFocus, :accessibilityElementIsFocused, :accessibilityFrame, :storedAccessibilityViewIsModal, :storedAccessibilityElementsHidden, :accessibilityHint, :accessibilityActivationPoint, :accessibilityTraits, :accessibilityLanguage, :accessibilityIdentifier, :accessibilityViewIsModal, :accessibilityElementsHidden, :storedAccessibilityTraits, :storedIsAccessibilityElement, :storedAccessibilityFrame, :storedAccessibilityActivationPoint, :"setAccessibilityElementsHidden:", :"setAccessibilityViewIsModal:", :"setAccessibilityHint:", :"setAccessibilityFrame:", :"setAccessibilityActivationPoint:", :"setAccessibilityTraits:", :"setIsAccessibilityElement:", :"setAccessibilityContainer:", :"setAccessibilityLanguage:", :"setAccessibilityIdentifier:", :accessibilityContainer, :accessibilityLabel, :"setAccessibilityValue:", :accessibilityValue, :"setAccessibilityLabel:", :isAccessibilityElement, :awakeFromNib, :classForPortCoder, :"replacementObjectForPortCoder:", :"methodDescriptionForSelector:", :"performSelectorOnMainThread:withObject:waitUntilDone:modes:", :"performSelector:onThread:withObject:waitUntilDone:modes:", :"performSelectorInBackground:withObject:", :"performSelector:onThread:withObject:waitUntilDone:", :"performSelectorOnMainThread:withObject:waitUntilDone:", :"performSelector:object:afterDelay:", :"performSelector:withObject:afterDelay:", :"performSelector:withObject:afterDelay:inModes:", :autoContentAccessingProxy, :classForCoder, :"replacementObjectForCoder:", :"awakeAfterUsingCoder:", :"implementsSelector:", :allowsWeakReference, :retainWeakReference, :classForKeyedArchiver, :"replacementObjectForKeyedArchiver:", :observationInfo, :"setObservationInfo:", :"willChange:valuesAtIndexes:forKey:", :"didChange:valuesAtIndexes:forKey:", :"willChangeValueForKey:withSetMutation:usingObjects:", :"didChangeValueForKey:withSetMutation:usingObjects:", :"didChangeValueForKey:", :"willChangeValueForKey:", :"removeObserver:forKeyPath:", :"addObserver:forKeyPath:options:context:", :"removeObserver:forKeyPath:context:", :"observeValueForKeyPath:ofObject:change:context:", :"setValuesForKeysWithDictionary:", :"dictionaryWithValuesForKeys:", :"setNilValueForKey:", :"validateValue:forKeyPath:error:", :"validateValue:forKey:error:", :"mutableArrayValueForKeyPath:",

Let there be Hello World

:"mutableArrayValueForKey:", :"mutableOrderedSetValueForKeyPath:", :"mutableOrderedSetValueForKey:", :"mutableSetValueForKeyPath:", :"mutableSetValueForKey:", :"setValue:forKeyPath:", :"valueForKeyPath:", :"valueForUndefinedKey:", :"setValue:forUndefinedKey:", :"valueForKey:", :"replacementObjectForArchiver:", :classForArchiver, :isNSValue__, :isNSString__, :isNSNumber__, :isNSArray__, :isNSDictionary__, :isNSData__, :isNSDate__, :isNSSet__, :isNSOrderedSet__, :isNSTimeZone__, :"CA_interpolateValues:::interpolator:", :"CA_distanceToValue:", :"CA_interpolateValue:byFraction:", :"CA_addValue:multipliedBy:", :CA_copyRenderValue, :CA_prepareRenderValue, :pep_onMainThread, :"pep_onOperationQueue:priority:", :"pep_onThread:immediateForMatchingThread:", :"pep_onThread:", :"pep_getInvocation:", :"pep_onOperationQueue:", :"pep_afterDelay:", :pep_onDetachedThread, :pep_onMainThreadIfNecessary, :releaseOnMainThread, :class, :"isEqual:", :hash, :retain, :release, :autorelease, :retainCount, :copy, :finalize, :"forwardInvocation:", :"isKindOfClass:", :"respondsToSelector:", :"doesNotRecognizeSelector:", :"performSelector:", :"performSelector:withObject:", :self, :mutableCopy, :debugDescription, :"forwardingTargetForSelector:", :"methodSignatureForSelector:", :superclass, :zone, :"performSelector:withObject:withObject:", :isProxy, :"isMemberOfClass:", :"conformsToProtocol:", :isFault, :"methodForSelector:"] (main)>> self.methods.count 464

Thats so much information to handle to understand what these do , iOS API docs on Dash is a better option, but you get what is possible How do we identify the relevant methods
(main)>> def useful_methods(variable); variable.public_methods.select {|k| k == k.downcase} - " ".methods ; end

So useful_methods is too long change it into something memorable for you, I will define it as "um", I am typing again as alias method is not available as RubyMotion is still not a 100% ruby implementation
def um(variable); variable.public_methods.select {|k| k == k.downcase} - " ".methods ; end

(main)>> um(hello) ... (main)>> useful_methods(hello) => [:table, :keyboard, :subtitle, :dismiss, :buttons, :layout, :context, :show, :title, :delegate, :message, :alpha,

This is more manageable, what did that magic method do, since RubyMotion is using native Objective-C as primitive all the methods are visible and they follow camelCase and colon in methods. additionally i have removed common methods derived in any string instance. Let us hide the message from console
(main)>> hello.dismiss

Bring it back
(main)>> hello.show

Let us add a title to the message window


(main)>> hello.title = "Title"

See this is fun. Let us try few more properties

Let there be Hello World

(main)>> hello.subtitle = (main)>> hello.message =

"Subtitle" "New Message"

Let us try something else


(main)>> hello.position => #<TypeError: unrecognized runtime type `{CGPoint=ff}'

We dont know what parameters are required but nothing big is lost, as the worst that might happen is the console crashes, but it is still a rare occasion. Whatever code works fine on console gets added to your editor and then gets commited to you repository and you are making progress one line at a time. Think about doing it on Xcode, each compile would take its time, and would be not the best way to develop quickly. You dont need to perfect code which would run on the first run, you just need to focus on the task in hand There are more than one way of doing anything in nearly every technology, but when you are learning learn one way of doing it first and go forward, over a period you would be a learnt man and can justify which is better as experience teaches you. WIP

Let there be Hello World

10

Read Code
Reading code is the best way to learn programming. I have been daily searching Hacker News , github and RubyMotion group to learn for how RubyMotion works, discover projects, problems faced by other people. I have tried to automate the process of downloading all the new projects for you to discover on your mac. If you follow the following steps you can checkout over 40 repositories as of now, more would be added in coming days

Clone the RubyMotion Cookbook repository


$ git clone https://github.com/railsfactory/rubymotion-cookbook.git Cloning into rubymotion-cookbook... remote: Counting objects: 143, done. remote: Compressing objects: 100% (88/88), done. remote: Total 143 (delta 53), reused 115 (delta 28) Receiving objects: 100% (143/143), 1.11 MiB | 178 KiB/s, done. Resolving deltas: 100% (53/53), done. $ cd projects $ sh clone_all.sh ....

It will take some time as about 100mb is downloaded directly from the repositories.

Projects which is being checked out are


https://github.com/seanho/Currency.git https://github.com/samchandra/Fonts.git https://github.com/stiller/LOLCatApp.git https://github.com/locousobscura/LastTime-iOS.git https://github.com/ps2/MotionGL.git https://github.com/caike/MotionHello.git https://github.com/siuying/NanoStoreInMotion.git https://github.com/rounders/RestKitTest.git https://github.com/siuying/RubyMotion-PocketCoreImage.git https://github.com/tnantoka/RubyMotionApps.git https://github.com/HipByte/RubyMotionSamples.git https://github.com/gpasq/RubyMotionZXingExample.git https://github.com/seanho/SimpleView.git https://github.com/siuying/SparrowInMotion.git https://github.com/rjowens/TableViewPullRefresh.git https://github.com/dalacv/WordSearcher.git https://github.com/anydiem/cocosmotion.git https://github.com/evanphx/distance_between.git https://github.com/aaronfeng/facebook-auth-ruby-motion-example.git https://github.com/jamesjn/fast_imgur_emailer-motion-ios.git https://github.com/latompa/griddler.git https://github.com/thbar/learning-rubymotion.git https://github.com/tvandervossen/motion-webview.git https://github.com/rjfranco/pragmatic-rubymotion.git https://github.com/clayallsopp/remote_model.git https://github.com/seanlilmateus/rmdialog.git https://github.com/macfanatic/rmotion.git https://github.com/ryw/rubymotion-experiments.git https://github.com/benr75/rubymotion-presentation.git https://github.com/cebartling/rubymotion-spikes.git https://github.com/MarkVillacampa/rubymotion-tabbar.git https://github.com/hellopatrick/wave.git https://github.com/spllr/TwitterApp.git https://github.com/siuying/hpple-motion.git https://github.com/rjowens/SplitViewControllerExample.git https://github.com/eatcpcks/rubymotion-bars.git https://github.com/malkomalko/motion-layouts.git https://github.com/sakisakira/IBOutletActionRubyMotion.git https://github.com/nlehuen/MotionCalc.git https://github.com/Watson1978/RubyMotion-Benchmark.git https://github.com/mordaroso/rubymotion-keychain-example.git

Read Code

11

Reading the code and Running the apps


You can read all the project code in your favorite text editor or IDE, I prefer Textmate. Running individual app is simple change into the directory and run rake and it compiles and runs.

Running all these apps at a stretch


$ # in projects folder $ sh run_all.sh

See all the apps running in sequence, in your simulator, stopping app technique one and two might be occasionally required.

Submit your app for this list


If you want your app be added, removed, please post a ticket https://github.com/railsfactory/rubymotion-cookbook/issues

Reading Apple iOS API Documentation


Dash is a nice app to read iOS Documentation Mac App Store link after downloading go to preferences and enable docsets and choose the libraries you would like to read and download, but for iOS you would need to download it inside xcode itself. iOS 5 documentation is about 500mb but still it is worth if you want to build or debug any non trivial apps I found this gem from Steven Ringo on RubyMotion Group WIP

Read Code

12

Best Practices
WIP

Best Practices

13

Controllers
WIP

Controllers

14

Views
WIP

Views

15

TableView
WIP

TableView

16

REPL: Interactive Console


WIP

REPL: Interactive Console

17

Core Location
WIP

Core Location

18

Core Data
WIP

Core Data

19

Camera
WIP

Camera

20

Audio
WIP

NAME
video

Audio

21

Graphics
WIP

Graphics

22

Addressbook
WIP

Addressbook

23

Core Location
WIP

Core Location

24

Cocoapods: using Objective C third party libraries/frameworks


WIP

Cocoapods: using Objective C third party libraries/frameworks

25

Facebook
WIP

Facebook

26

Consuming ReSTful API


WIP

Consuming ReSTful API

27

TestFlight
WIP

TestFlight

28

App Store
WIP

App Store

29

You might also like