Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Objective-C vs. RubyMotion!

Objective-C vs. RubyMotion!

Presented at ChicagoRuby, Jan 8 2013.

David Demaree

January 08, 2013
Tweet

More Decks by David Demaree

Other Decks in Programming

Transcript

  1. View Slide

  2. VS
    OBJECTIVE-C RUBYMOTION

    View Slide

  3. David Demaree
    Typekit UX & Ruby engineer
    at Adobe
    @ddemaree
    log.demaree.me
    [email protected]



    View Slide

  4. Objective-C
    Invented in 1983, adopted by
    NeXT, currently maintained by
    Apple
    Pretty much used only for
    Apple platforms
    Statically typed object-
    oriented language
    Strict superset of C
    Preprocessed

    View Slide

  5. RubyMotion
    Implementation of Ruby 1.9
    (sort of) on LLVM and the
    Objective-C runtime
    Closed-source compiler,
    available commercially for $199
    (+ annual support fee)
    Open-source build tools, based
    on Rubygems and Rake

    View Slide

  6. WHY IS RUBYMOTION
    BETTER THAN ___?

    View Slide

  7. View Slide

  8. View Slide

  9. iOS Developer Agreement
    3.3.1 Applications may only use Documented APIs
    in the manner prescribed by Apple and must not
    use or call any private APIs. Applications must be
    originally written in Objective-C, C, C++, or JavaScript
    as executed by the iPhone OS WebKit engine, and only
    code written in C, C++, and Objective-C may compile
    and directly link against the Documented APIs (e.g.,
    Applications that link to Documented APIs through an
    intermediary translation or compatibility layer or tool
    are prohibited).

    View Slide

  10. iOS Developer Agreement
    3.3.1 Applications may only use Documented APIs
    in the manner prescribed by Apple and must not
    use or call any private APIs. Applications must be
    originally written in Objective-C, C, C++, or JavaScript
    as executed by the iPhone OS WebKit engine, and only
    code written in C, C++, and Objective-C may compile
    and directly link against the Documented APIs (e.g.,
    Applications that link to Documented APIs through an
    intermediary translation or compatibility layer or tool
    are prohibited).

    View Slide

  11. Ruby source code
    ObjC libraries
    Cocoa frameworks
    Native iOS app
    RubyMotion calls Cocoa frameworks directly

    View Slide

  12. PhoneGap app
    (HTML/CSS/JS)
    Objective-C
    runtime
    Cocoa app
    (Objective-C)
    Cocoa app
    (RubyMotion)
    Compiles to Obj-C bytecode
    Compiles to Obj-C bytecode
    PhoneGap
    cross-platform
    runtime

    View Slide

  13. Apple

    View Slide

  14. 5by5.tv/hypercritical/66

    View Slide

  15. CODE

    View Slide

  16. VS
    Objective-C Ruby syntax

    View Slide

  17. CAUTION
    Now entering nerd zone

    View Slide

  18. In the beginning, there was
    OBJECTIVE-C RUBY
    PYTHON
    JAVA SCALA
    GROOVY
    SMALLTALK

    View Slide

  19. Learning Objective-C
    Programming with
    Objective-‐C
    bit.ly/objcprimer apeth.com/iOSBook cocoabook.com

    View Slide

  20. Learning Ruby & RubyMotion
    All titles available at pragprog.com

    View Slide

  21. Statically compiled
    No require
    No eval
    No Proc#binding
    No define_method
    Named parameters
    RubyMotion
    !≈
    Ruby

    View Slide

  22. Objective-C

    View Slide

  23. Classic Obj-C Modern Obj-C
    Brackets everywhere Properties & dot syntax
    Verbose code for working with
    basic object types
    Object literals
    Manual memory management ARC
    No blocks Blocks!

    View Slide

  24. Objective-C

    View Slide

  25. Ruby can do almost
    anything Obj-C can do,
    BUT SIMPLER

    View Slide

  26. @interface DDVenue : NSObject
    @property (strong) NSString *name;
    @property (strong) NSString *address;
    @property (strong) CLLocation *location;
    - (CLLocationDistance)distanceFromLocation:(CLLocation *)otherLocation;
    @end
    @implementation DDVenue
    @synthesize name, address, location;
    - (CLLocationDistance)distanceFromLocation:(CLLocation *)otherLocation
    {
    return [self.location distanceFromLocation:otherLocation];
    }
    @end

    View Slide

  27. class Venue
    attr_accessor :name, :address, :location
    def distanceFromLocation(location)
    self.location.distanceFromLocation(location)
    end
    end

    View Slide

  28. class Venue
    attr_accessor :name, :address, :location
    def distanceFromLocation(location)
    self.location.distanceFromLocation(location)
    end
    end
    Everything inherits from (NS)Object

    View Slide

  29. class Venue
    attr_accessor :name, :address, :location
    def distanceFromLocation(location)
    self.location.distanceFromLocation(location)
    end
    end
    Everything inherits from (NS)Object
    Dynamic/“duck” typing

    View Slide

  30. class Venue
    attr_accessor :name, :address, :location
    def distanceFromLocation(location)
    self.location.distanceFromLocation(location)
    end
    end
    Everything inherits from (NS)Object
    Dynamic/“duck” typing
    Implicit return

    View Slide

  31. class Venue
    attr_accessor :name, :address, :location
    def distanceFromLocation(location)
    self.location.distanceFromLocation(location)
    end
    end
    Everything inherits from (NS)Object
    Dynamic/“duck” typing
    Implicit return All dot syntax, all the time

    View Slide

  32. class Venue
    attr_accessor :name, :address, :location
    def distanceFromLocation(location)
    self.location.distanceFromLocation(location)
    end
    end
    Everything inherits from (NS)Object
    Dynamic/“duck” typing
    Implicit return All dot syntax, all the time
    No interface file required

    View Slide

  33. @interface DDFood : NSObject {
    BOOL isPizza;
    }
    - (void)setIsPizza:(BOOL)value;
    @end
    @implementation DDFood
    - (void)setIsPizza:(BOOL)value {
    isPizza = value;
    }
    @end
    class Food
    def isPizza=(pizzaness)
    @isPizza = pizzaness
    end
    def isPizza!
    @isPizza = true
    end
    def isPizza?
    @isPizza ||= false
    end
    end
    Instance vars must be declared Anything with an @-sigil is an ivar

    View Slide

  34. // YellingString.rb
    class String
    def yell
    self + "!"
    end
    end
    "Kind of awesome".yell.yell.yell
    #=> "Kind of awesome!!!"
    // NSString+Yelling.h
    @interface NSString (Yelling)
    - (NSString*) yell;
    @end
    // NSString+Yelling.m
    @implementation NSString (Yelling)
    - (NSString*) yell {
    return [self
    stringByAppendingString:@"!"];
    }
    @end
    [@"Kind of awesome" yell];
    //=> @"Kind of awesome!"
    Classes extended via categories Classes can be reopened at any time

    View Slide

  35. Ruby has real namespaces
    NSString, GBFont, DDCoreDataManager
    MyApp::Venue, MyApp::Item,
    CoreData::Manager
    Objective-C class names are prefixed
    Ruby classes/modules can be nested inside each other

    View Slide

  36. Multiple inheritance via mixins
    module StaticTableViewController
    CellInfo = Struct.new(:text, :accessory_type, :action)
    def tableView(tableView, cellForRowAtIndexPath:indexPath)
    cell = self.infoForCells[indexPath.row]
    # Create and return a UITableViewCell
    end
    end
    module SettingsViewController < UITableViewController
    include StaticTableViewController
    end

    View Slide

  37. class Thing < Struct.new(:name)
    def has_hat?
    false
    end
    end
    module Hat
    def has_hat?
    true
    end
    end

    View Slide

  38. myThing = Thing.new("Cat")
    myThing.has_hat? #=> false
    myThing.extend(Hat)
    myThing.has_hat? #=> true

    View Slide

  39. Blocks!
    class PlaceFinder
    def self.placeFinderWithBlock(&block)
    newFinder = self.alloc.init
    yield newFinder if block_given?
    return newFinder
    end
    end
    @finder = PlaceFinder.placeFinderWithBlock do |finder|
    finder.location = CLLocation.alloc.initWithLatitude(lat,
    longitude:lng)
    finder.numberOfResults = 10
    end

    View Slide

  40. HTTP.get("http://github.com/ddemaree") do |response|
    p response.body.to_str # prints the response's body
    end
    @singleton = nil
    Dispatch.once do
    @singleton ||= self.alloc.initWithOptions({})
    end
    Providing a completion callback for a HTTP request
    Initializing a singleton in a thread-safe way

    View Slide

  41. WHAT’S SO GREAT
    ABOUT SIMPLER?

    View Slide

  42. Less boilerplate

    View Slide

  43. Code is easier to read and
    more self-documenting

    View Slide

  44. It… feels good?

    View Slide

  45. What do we give up by
    using RubyMotion?

    View Slide

  46. No compile-time warnings

    View Slide

  47. No direct access to the C layer

    View Slide

  48. Enums and C structs
    typedef NS_ENUM(NSUInteger, GBListSettingsSection){
    GBListSettingsBudgetToggleSection,
    GBListSettingsSectionLock,
    GBListSettingsSectionEmail,
    GBListSettingsSectionAll
    };
    - (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {
    if (section == GBListSettingsBudgetInclusionSection) {
    return 2;
    }
    }
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return GBListSettingsSectionAll;
    }

    View Slide

  49. class PlacesViewController < UITableViewController
    SECTIONS = [:budget, :lock, :email]
    def tableView(tableView, numberOfRowsInSection:section)
    sectionName = SECTIONS[section]
    if sectionName == :budget
    return 2
    end
    end
    def numberOfSectionsInTableView(tableView)
    SECTIONS.length
    end
    end

    View Slide

  50. The Uncanny Valley

    View Slide

  51. > motion ri UIView
    RubyMotion `ri` documentation

    View Slide

  52. RubyMotion’s “C” layer

    View Slide

  53. RubyMotion’s C-like APIs
    Dispatch.once { @singleton ||= self.new }
    errorPtr = Pointer.new(:object)
    ABAddressBookCreateWithOptions(nil, errorPtr)
    Pointers are objects
    Functions are wrapped as methods on the Object class
    Grand Central Dispatch is wrapped as the Dispatch module

    View Slide

  54. “Sexy” DSLs

    View Slide

  55. Covering all of Cocoa with newer,
    simpler DSL abstractions is a stated
    goal of RubyMotion’s creators

    View Slide

  56. View Slide

  57. alert = UIAlertView.alloc.initWithTitle "Hey, buddy",
    message: "Buzz off!",
    delegate: nil,
    cancelButtonTitle: nil,
    otherButtonTitles: nil
    alert.show()
    App.alert("Hey, buddy", message: "Buzz off!") do |alert|
    # You can perform any additional configuration on the
    # UIAlertView object here, using the `alert` variable
    end
    BubbleWrap
    Standard Cocoa API (in RubyMotion)

    View Slide

  58. github.com/alloy/MotionData

    View Slide

  59. PhoneGap app
    (HTML/CSS/JS)
    Objective-C
    runtime
    Cocoa app
    (Objective-C)
    Cocoa app
    (RubyMotion)
    Compiles to Obj-C bytecode
    PhoneGap
    cross-platform
    runtime
    RubyMotion
    DSLs?

    View Slide

  60. TOOLS

    View Slide

  61. VS
    Bring your own Xcode

    View Slide

  62. VS
    Familiar (if you’re coming
    from Ruby/open-source
    development)
    Lighter-weight, which can
    be faster / more nimble
    Have it your way
    Supported by Apple
    Designed specifically for
    Cocoa/Cocoa Touch app
    development
    Excellent integrated
    documentation & code
    completion

    View Slide

  63. Xcode knows more about
    Cocoa & Objective-C than
    most of us will ever forget

    View Slide

  64. Context-sensitive code completion

    View Slide

  65. Integrated documentation

    View Slide

  66. Real-time error checking (via static analysis)

    View Slide

  67. “Using XCode is like driving a very used, modern car - it
    routinely breaks down, freezes and screws up the rest of my
    system and there is no way to understand what it wrong
    because all the parts are hidden from you. For example, it
    will stop compiling and simply freeze, acting like it's doing
    something. It will kill other processes and cause them to
    freeze (terminal processes simply stop getting cycles). It will
    stop responding to step over, step in, etc actions.
    “If there is any way for you to avoid XCode, do so. So far,
    I have had to force quit 4 times since 9:00 AM.”

    View Slide

  68. better?
    Is

    View Slide

  69. > motion create my_project

    View Slide

  70. Motion::Project::App.setup do |app|
    # Use `rake config' to see complete project settings.
    app.name = 'GiftBox'
    app.version = "2.0"
    app.interface_orientations = [:portrait]
    app.identifier = "me.demaree.GiftBox2"
    app.short_version = "190"
    app.frameworks += ["CoreData"]
    end
    RubyMotion configuration DSL

    View Slide

  71. View Slide

  72. View Slide

  73. View Slide

  74. github.com/mattt/shenzhen

    View Slide

  75. TESTING

    View Slide

  76. TESTING ON IOS

    View Slide

  77. Client-side applications
    are big, messy balls of
    SHARED STATE

    View Slide

  78. iOS client-side testing

    Full-stack JavaScript
    testing?

    View Slide

  79. QUESTIONS

    View Slide

  80. Should I learn Cocoa on
    Objective-C first, or RubyMotion?

    View Slide

  81. Learn Objective-C
    Because it’s awesome (really)

    View Slide

  82. Learning Objective-C
    Programming with
    Objective-‐C
    bit.ly/objcprimer apeth.com/iOSBook cocoabook.com

    View Slide

  83. View Slide

  84. If you use RubyMotion, try to at
    least learn the Cocoa APIs

    View Slide

  85. Should I use RubyMotion?

    View Slide

  86. How I use RubyMotion today
    Personal projects
    Rapid prototyping
    Internal apps?

    View Slide

  87. Your questions

    View Slide

  88. David Demaree
    Typekit UX & Ruby engineer
    at Adobe
    @ddemaree
    log.demaree.me
    [email protected]



    View Slide