Might as well get a bare-bones UITableView controller/data-source banged out. I'll inevitably copy & paste that code into other projects. And later, detecting iPad and iPhone, and making different ViewControllers to deal with them.

UITableView

Working off the same MyApplicationController that I did last time, I made a very simple UITableViewDataSource implementation, using just an array and a basic reused text cell.

class MyApplicationController < UIViewController

  def viewDidLoad
    @data = [
      {first: 'firsty', last: 'McLasty'},
      {first: 'humphrey', last: 'bogart'},
    ]
    @table = UITableView.alloc.initWithFrame(view.frame, style: UITableViewStylePlain)
    @table.dataSource = self
    view.addSubview(@table)
  end

  def tableView(tableView, cellForRowAtIndexPath:indexPath)
    cell = tableView.dequeueReusableCellWithIdentifier(cell_identifier)
    #
    if not cell
      cell = UITableViewCell.alloc.initWithStyle UITableViewCellStyleDefault, reuseIdentifier:cell_identifier
    end

    cell.textLabel.text = "#{@data[indexPath.row][:first]} #{@data[indexPath.row][:last]}"

    return cell
  end

  def cell_identifier
    @@cell_identifier ||= 'Cell'
  end

  def tableView(tableView, numberOfRowsInSection: section)
    case section
    when 0
      @data.length
    else
      0
    end
  end

end

Cryptic (lack of!) error message

That was pretty simple, and very tedious, too. I had an inexplicable crash whenever I tried to scroll the table. I thought maybe the most recent update of RubyMotion (which was just a few hours ago - version 1.2) broke things, but it turned out to be a call to cell.autorelease. Because RubyMotion handles garbage collection, it was not happy that I tried to help. The error message was:

Command failed with status (1): [DYLD_FRAMEWORK_PATH="/Applications/Xcode.a...]

Tasks: TOP => default => simulator
(See full trace by running task with --trace)

So I ran it again with --trace

Command failed with status (1): [DYLD_FRAMEWORK_PATH="/Applications/Xcode.a...]
.../ruby/1.9.3-p0/lib/ruby/1.9.1/rake/file_utils.rb:53:in `block in create_shell_runner'
.../ruby/1.9.3-p0/lib/ruby/1.9.1/rake/file_utils.rb:45:in `call'
.../ruby/1.9.3-p0/lib/ruby/1.9.1/rake/file_utils.rb:45:in `sh'
.../ruby/1.9.3-p0/lib/ruby/1.9.1/rake/file_utils_ext.rb:39:in `sh'
/Library/RubyMotion/lib/motion/project.rb:75:in `block in '
... and a long list of calls in rake/task.rb ...

No help there, but eventually I remembered "random app crashing... must be memory related!"

  • screenshot_tableview.png

    Screenshot of the UITableView on iPhone

WOW, right :-)

iPad and iPhone

Going back to yesterday's labels and buttons, I wanted to see what it looked like to program for iPad, and how to tell at runtime what device is running.

First, to target iPad and iPhone, you need to change the default device_family in your Rakefile:

Motion::Project::App.setup do |app|
  # Use `rake config' to see complete project settings.
  app.name = 'The best app ever'
  app.device_family = [:iphone, :ipad]
end

You can either specify the device using

rake simulator device_family=ipad

Or by selecting "iPad" from the Hardware > Device menu of the simulator.

I took a page out of matt aiometti's book, and added a ipad? method to the Kernel:

class Kernel

  def ipad?
    UIDevice.currentDevice.userInterfaceIdiom == UIUserInterfaceIdiomPad
  end

end

Next, make two subclasses of MyApplicationController, specifying the left and top offsets:

class MyIphoneController < MyApplicationController
  def init
    @left = 20
    @top = 40
    super
  end
end

class MyIpadController < MyApplicationController
  def init
    @left = 40
    @top = 80
    super
  end
end

In AppDelegate, instantiate one or the other:

application.setStatusBarStyle(UIStatusBarStyleBlackTranslucent)

if ipad?
  @window.rootViewController = MyIpadController.alloc.init
else
  @window.rootViewController = MyIphoneController.alloc.init
end

@window.rootViewController.wantsFullScreenLayout = true

And then an arbitrary change in MyApplicationController, just to prove something is "going on"

...
device = ipad? ? 'iPad' : 'iPhone'
label.text = "Label of size #{size} on #{device}"
...
  • screenshot_iphone_labels.png

    Screenshot Iphone Labels Png

  • screenshot_ipad_labels.png

    Screenshot Ipad Labels Png