Did I make a UIImageView? Nope! I made a UITableView. a rubymotion thought by colinta
View the source at github.com/colinta/thoughts
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!"
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}" ...