Friday, August 31, 2012

RubyMotion : Gems Are Not Being Compiled / Built / Included

I was working on the most basic of apps, really nothing complicated at all, and trying to include BubbleWrap.  But the first time I tried to use anything (in this case, Device.screen.width) I was getting a name error - as if BW was not included.

I had  require 'bubble-wrap' in my Rakefile. I'd done a gem install bubble-wrap.  That wasn't it.  What appeared to be happening was that over in build/iPhoneSimulator-5.1-Development/objs there should have been a /Users/dmorin/.rvm/... directory where my required gems were getting copied, and that directory didn't exist.

I double checked everything, I ran "rake clean", I could not for the life of me make it include that directory.  I even created a brand new empty motion directory and included bubble-wrap in it so that this was literally the single line change I made from default -- and it compiled.  Go figure.

Finally, I found it.  I had been modifying some sample code that I found online, and it was this line:

app.files = Dir.glob(File.join(app.project_dir,'app/lib/**/*.rb'))|

Dir.glob(File.join(app.project_dir, 'app/**/*.rb'))

I'd seen something like that trick before, and it seemed like something I understood - basically saying that you're going to put some common code into a /lib subdirectory, so compile that first in order to make it available to your primary code.

But that's not quite accurate.  I think there was a mistake in the code that I copied, because what this does is to make app.files *only* point the files in your app/ and app/lib directory - completing removing any gems from the filepath.  You can check this with rake config - performing this command on a brand new directory will return all of your gem paths (whether it's .rvm or not), but doing so in the directory where the above line is included in the Rakefile?  Shows all my app/ code, but no gems.

In my case it turns out I don't need that line at all, so I've removed it.  Soon as I did that, my gems were included.  If you do need to manipulate app.files and the way things are included, you'll want to append or otherwise manipulate the existing list, not just replace it with a plain old equals!

Friday, August 10, 2012

Rails MVC vs iOS MVC

If your primary experience with Model View Controller (MVC) has been via Ruby on Rails, and then you switch over to iOS (iPhone / iPad) programming, see that it also supports MVC and think, "Oh, cool, I already know that!"  Not so fast.

I am not expert at either of these technologies, but let me put it in the best terms I can.  In the Rails world, the controller is primarily associated with manipulating the model.  You have a Person object, you have a PersonController.  That PersonController has actions like index (show a list of Person objects), show (a single Person), edit/update, create/save, destroy and so on.  Things that you can do with that object.  Each action, in general, has a view.  To the point where the default behavior of an action called "foo" on the PersonController is to assume that there is a file called foo in the /views/person directory.

In iOS world, each controller handles a single view.  I'm still trying to get my head around it.  I keep thinking of the View as an entirely separate object that I instantiate and "connect" to the controller in some way, such that the controller's only real job is to take in some user input, manipulate some stuff, and then let the next view do its thing.

Not really.  In fact, the controller can go ahead and just instantiate a UIView object and start populating it.  There' a method called viewDidLoad, that gets called when the view is all loaded.  Fair enough.  Where is that method?  Is there a didLoad() method on UIView?  Nope!  It's on the controller.  So it's practically hard coded in the framework that a controller deals with "the view" and you don't get to trick it into managing many views.

I don't yet fully get it.

UPDATE - As I do more googling on stuff like "switch UIView" I'm learning some techniques for how to manage multiple views inside a controller.  It's not quite the same thing as having a specific view associated with a specific action like Rails does, but it's inaccurate to say that a controller can only handle a single view at a time. It's more like, "The controller has a pointer to a view.  You are free to swap out and/or otherwise regenerate that view according to whatever rules you like."  So I don't think I have to have a PeopleIndexController and a PeopleShowController and a PeopleEditController...