My Unboxings

16
1 Creating Our Very First Mac Application With Ruby Creating a new project After starting up Xcode: 1. Select File 2. Select New Project A dialog window as shown below should appear. From this window 1. Select MacRuby application 2. Click on Choose… A file save dialog should now appear as displayed below. In this window: 1

description

We Do All New Device Unboxings

Transcript of My Unboxings

Page 1: My Unboxings

1Creating Our Very

First Mac ApplicationWith Ruby

Creating a new project

After starting up Xcode:

1. Select File2. Select New Project

A dialog window as shown below should appear.From this window

1. Select MacRuby application2. Click on Choose…

A file save dialog should now appear as displayedbelow.

In this window:

1

Page 2: My Unboxings

1. Type in BornToBeAlive as our project name.2. Click on Save.

A new window should now appear representing thenewly created project in the Xcode environment.

By the time of this writing our environment is setup totarget OS X 10.5 (Leopard). As mentioned before, we’regoing to target OS X 10.6 (Snow Leopard) seeing as wewant to utilize the most mature Cocoa API and platform.As such we need to set this target environment to OS X10.6 in the overview popup menu.

Now that that’s been dealt with, we can finally reallystart working on our application.

Designing our InterfaceBefore we’re going to write even a single line of code,

let’s first start off by designing the user interface to ourapplication. To do this, we first need to discuss how ourprogramming environment deals with this kind of infor-mation.

Certain information about our interfaces, in particularthe one’s we’ve created using Interface Builder (the UIdesign application of Xcode) are usually stored in bundlescalled NIB files.

As of Xcode 3, these are actually stored in files withthe xib file extension as opposed to the nib file extension.Worry not however, as they are just different formats forstoring the same information: where xibfiles appear to berepresented as XML text files, a nib file is an archive. Moreimportantly however, the differencebetween xib and nib files are that the former will be com-

2 Working With Mac Programming

Page 3: My Unboxings

piled within the executable and will not appear in thefinal .app bundle.

In general, Xcode will ultimately know what to do withthese files and how to treat them. It is for this reason thatwe’ll refer to both formats as nib files and basically assumeno distinction between them.

In the Groups & Files panel, expand the NIBFiles group.

In this panel

1. Double click on MainMenu.xib

This action should result in Interface Builder firing upfor this MainMenu.xib file. Various windows of InterfaceBuilder should now be visible to you.

In the MainMenu.xib window:You see a collection of objects and proxy objects that

are necessary for describing our user interface. Theobjects displayed in this window are objects that describeour application’s user interface and are stored in a freezedried manner, i.e. serialized. Upon loading the NIB file,they get thawed and instantiated again.

In light of this, it is considered good practice to storeonly one window object per nib file. This way, we onlyload in the windows when we really need them (thus con-serving memory) and will keep our design more maintain-able too as each window and its components will be con-tained by its own NIB file. The latter will allow us to pos-sibly recycle NIB files too in other projects.

Strictly speaking, we also shouldn’t store a window inour MainMenu.xib as is now the case, but in order to load

Creating Our Very First Mac Application… 3

Page 4: My Unboxings

this in, we require a notion of delegates. The latter issomething we’ll discuss in a later article so for now, we’llkeep the window object in MainMenu.xib.

For now:

1. Double click on Window

This should put the focus on our initial window and viathe inspector, we can edit some of its properties, such asthe title of the window instance.

While having selected the Window in the Main-Menu.xib window, in the inspector window:

1. Select the first tab, so that the inspector window is dis-playing the Window Attributes.

2. Edit the Title field to Born to be Alive3. Hit the enter key

Your window should now bare the title Born to be Alive.How exciting!

Let’s add a Label to this window proclaim this messageof life even bigger. To add cocoa components to ourwindow, we need to drag and drop them fromour Library panel to the window we want to add them to.

In the Library panel:

1. Set the focus on the search field at the bottom ofthe Library panel.

2. Type in Label. Notice that as we type character percharacter, the components get filtered based on ourquery.

Your Library panel should now display a few optionsfor labels and should look something like the following:

4 Working With Mac Programming

Page 5: My Unboxings

Note that my Library panel will most likely displaymore options here in terms of labels as I’ve also installedthe BWToolkit [http://brandonwalkin.com/bwtoolkit/] palette too. We won’t be using any of thosecomponents for our MacRuby applications though, so it’ssafe for you to ignore them for now.

Now it’s time to actually add the Label component toour window. As mentioned earlier on, we do this bysimply dragging and dropping the Label icon fromour Library panel to the window we want to add it to.Doing so should result in something similar to the fol-lowing:

Great! Let’s rename the newly added Label to some-thing more fitting. In the window displayed above:

1. Double click on the newly added Label. This shouldnow open up the ability to edit value of this Label.

2. Type in Born3. Hit the enter key.

Your window should now look something like this:Wouldn’t it be fun if we would have a button that we

could press to unveil the full message of life? Let’s do justthat by adding a button to the window we’re designing.

In the Library panel:

1. Type Button in the search box at the bottom ofthe Library panel. In a similar fashion as the label, itshould filter away the components that do not matchthe Button search description.

Whoah, so many buttons! Let’s just stick with thefirst shiny one for now.

Creating Our Very First Mac Application… 5

Page 6: My Unboxings

2. Drag and drop the first button that appears in the fil-tered selection to our window. Depending on whereyou dragged and dropped the button to, your windowshould now look something like this:

3. Double click on the newly added button to be able toedit its title.

4. Type in Unveil full message5. Hit the enter key.

Your window should now be shaping up pretty nicelyand look something like:

We can actually build this project at this stage and seewhat we’ve just designed in the form of a real application!Indeed, the standard MacRuby cocoa template has set upmost of the boilerplate to get us started. At a later stage,we’ll dive into the details of the bootstrapping process, butfor now let’s just assume that it set it up all correctly andsave our changes by selecting File->Save from the Inter-face Builder main menu.

Compiling is not the task of Interface Builder, but thetask of Xcode so let’s switch back to Xcode. In the projectwindow, click on the Build and Run button in its toolbar.

After compiling for a few seconds and linking all thedependencies, your new application should launch in yourOS X dock, and in particular, the window you justdesigned should show up.

Clicking on the Unveil full message button doesn’t do alot though, but that should come as no surprise seeing aswe’ve only been designing the interface up to this point.We haven’t yet specified what should happen if onepresses the Unveil full message button button.

6 Working With Mac Programming

Page 7: My Unboxings

In terms of Model-View-Controller (MVC) [http://en.wikipedia.org/wiki/Model_view_controller] (a sepa-ration of concerns design pattern Cocoa relies heavily on),we need a controller to handle this kind of user input.

Writing our very first controller in MacRubyAs mentioned in the previous section, Cocoa was

designed with the MVC paradigm in mind. Within thisparadigm, we need some kind of controller layer toprocess the input provided by the user. This input rangesfrom keyboard events to mouse events. For our intentsand purposes, we’re interested in handling mouse eventson our Unveil full message button. In order to be able to dothat, we need to create a controller that will be able to dealwith that.

Also, we may want to process events employed by theuser onto the window itself. This would normally requirea NSWindowController instance. Taking in mind we wantto process events from components within the window aswell, we could choose to create a separate controller forthese components as well, but that would likely makethings overly granular, especially for the simple scenariowe’re currently dealing with.

So in place of the latter, we can also just choose to con-solidate the ability to process the events of a window andits components all together into a subclass of NSWindow-Controller. This allows us to handle the general case ofcontrolling an NSWindow as well as specify our ownactions for handling the components contained byour NSWindow.

Creating Our Very First Mac Application… 7

Page 8: My Unboxings

To do this, in the Groups & Files panel, expandthe BornToBeAlive project as displayed below by clickingon the triangle next to it.

In this expanded project outline view:

1. Right click (or ctrl+click) on Classes2. Select Add->New File

A new window should now appear giving you theoptions of what kind of new file you would like to add.

1. From the Ruby user templates, select Ruby File.2. Click on Next

This will open up a Save File dialog.

1. Type in MyWindowController.rb as the name for thenew Ruby file.

2. Click on Finish.

Your window should now look something like this:As decided upon earlier, we now need to implement

our MyWindowController class in a consolidated way suchthat it can control both the window and the elements con-tained by that window. We will achieve this by imple-menting MyWindowController as being a subclass ofNSWindowController, and in doing so, specialize theNSWindowController class for our window.

In the code editor, type in:

class MyWindowController < NSWindowControllerend

Tres bien! But how do we access the label to modify itsvalue after a user has clicked on the Unveil full mes-sagebutton?

8 Working With Mac Programming

Page 9: My Unboxings

Well, according to the Apple cocoa documentation onNSWindowController [http://developer.apple.com/Mac/library/documentation/Cocoa/Reference/Applica-tionKit/Classes/NSWindowController_Class/Refer-ence/Reference.html#//apple_ref/occ/instm/NSWin-dowController/setWindow:], it is capable hold a refer-ence to the window it controls/manages. Instinctively, weassume that through this reference, we could access theelements of the window.

Even though this is kind of true, the NSWindow classwas designed for general cases as well and not just our spe-cific window. This means that its design is well composed[http://en.wikipedia.org/wiki/Object_composition] andthat it will be rather tedious to acquire a reference to theelement of the window we’re interested in manipulating.Most likely, it will involve a lot of chaining query callswhich violates the principle of least knowledge [http://en.wikipedia.org/wiki/Law_Of_Demeter].

To drive the point home, accessing an element in sucha fashion in general will look something like:window.view.subviews[0]

A non-food solution to this would be to subclassour NSWindow to hold a direct reference to the elementswe’re interested in manipulating, but that would requirean assumption in terms of type seeing as ourNSWindow-Controller only deals with NSWindow and not OurSpecific-Window.

Taking all this into account, it’s probably just better togive our MyWindowController a direct reference to the ele-ment of the window we’re interested in manipulating.

Creating Our Very First Mac Application… 9

Page 10: My Unboxings

In our particular case, we’d like to change the label’sstring value after the user has clicked on the Unveil fullmessage button to show the true message of life. Thismeans we need a reference to the label within ourMyWin-dowController and as such our code listing of MyWindow-Controller now is:

class MyWindowController < NSWindowController attr_accessor :my_labelend

In Cocoa, such a reference is usually referred to asan outlet, in our case, representing the metaphor of“being able to plug a label object into the outlet”. C’estbon indeed!

We now need to define the action to be taken when auser has clicked on our Unveil full message button. Youmight be wondering right now whether or not we alsoneed a reference to the button from withinMyWindow-Controller as was the case for the label. This however, isnot necessarily the case for us seeing as the button — aninstance of NSButton — is an action emitter. More specifi-cally, an NSButton [http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/Appli-cationKit/Classes/NSButton_Class/Reference/Refer-ence.html] inherits from NSControl [http://devel-oper.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSCon-trol_Class/Reference/Reference.html#//apple_ref/occ/cl/NSControl]and NSResponder [http://devel-oper.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSRes-ponder_Class/Reference/Reference.html#//apple_ref/

10 Working With Mac Programming

Page 11: My Unboxings

occ/cl/NSResponder] allowing it to receive user input(e.g. mouse events) and convert these to action eventsand dispatch the latter to our code. We may touch base onthis subject in more detail in a later article, but for now,suffice it to say that we don’t need such a property refer-ence.

When the button receives a mouse event from the userthat is of our interest, i.e. a click event, it will convert thisevent into a click action and try to dispatch the actionmessage to our code. To that end, the button expects us toprovide an object with an action handler method tohandle the action on delivery. In Cocoa terminology, thisobject containing the action handler method is referred toas the target of the button.

An action handler method in MacRuby has a distinctmethod signature: it is a method with one parameternamed sender. It is important to adhere to this rule foraction handler methods as Xcode and Interface Builderwill only then recognize them as being actions.

Let’s open up our code editor in Xcode for MyWindow-Controller.rb and change the listing to:

class MyWindowController < NSWindowController attr_accessor :my_label

def unveil_full_message_clicked(sender) @my_label.stringValue = “42” endend

Here, we’ve added the unveil_full_mes-sage_clicked action, which will change the string-Value property of our label to the true message of life.Excellent! We’ve now set up all our code, and what

Creating Our Very First Mac Application… 11

Page 12: My Unboxings

remains now is to tell our button to who it should dispatchits action to.

We can setup this target-action for our button program-matic, but Interface Builder provides us with a visual solu-tion for setting these up as well. For the sake of clarity andconvenience, the visual solution that we’ll go over with ina few moments enjoys our preference for now.

Hooking our MyWindowController up to our windowIn the previous sections we’ve gone from designing our

window to providing an implementation for ourMyWin-dowController class. They still need to be hooked up toone another however as they are now still disjoint entitiesthat don’t know of eachothers existence. In this section,we’ll describe how we’ll be able to hook these things upvisually using Interface Builder.

In Xcode:

1. Double click on MainMenu.xib to open up InterfaceBuilder for this nib file.

As we’ve discussed earlier, objects are stored in a freezedried manner in our NIB file that get “thawed for use”when the NIB file is loaded again. In this case, we need aninstance of MyWindowController to hook it up to ourfreeze dried window instance.

In Interface Builder in the Library Panel:

1. Type in NSObject in the search field.2. Drag and drop the Object from the panel to the Main-

Menu.xib window of Interface Builder. This will createa new freeze dried object in the NIB file that will beinstantiated when the NIB file gets loaded in.

12 Working With Mac Programming

Page 13: My Unboxings

3. Select the object.

In the Inspector panel:

1. Click on the Object Identity tab.As we can see, the object is of class type NSObject.

We need to change this to be MyWindowController tolet this object be an instance of that type.

2. In the class identity field, type in MyWindowController.Our object is now of type MyWindowController.

Tres bien!

Now that we’ve created a freeze dried MyWindowCon-troller object, it’s time to hook it up to our windowinstance.

Recall from the code listing on MyWindowCon-troller that we have defined an accessor — i.e. outlet — forour label, but have not yet set this property. In particular,we need to set the my_label property of ourMyWindow-Controller instance to point to the label of our window. InCocoa jargon, we need to “plug our window’s label intoour MyWindowController‘s my_label outlet”.

In the MainMenu.xib window of Interface Builder:

1. Hold down the right button (or hold ctrl+click) onthe MyWindowController object and drag your mouseto the label in the designer.

2. Release the right mouse button above the label. Apopup menu as displayed below should now appearshowing you the outlets to which you can hook thelabel up to.

Creating Our Very First Mac Application… 13

Page 14: My Unboxings

3. Click on my_label in the Outlet popup menu to hookthe label in the window up to our MyWindowCon-troller‘s my_label property.

Our MyWindowController now knows what object itshould refer to when we use @my_label in MyWindow-Controller. What remains is to set up the target-action forour button to our controller’s action handler method.We’re almost there indeed!

To set the target-action for our button:

1. Hold down the right mouse button (or ctrl+click) onthe button in our window and drag to our My WindowController object in the MainMenu.xib window asillustrated below.

2. Release the right mouse button. A popup menu shouldnow appear displaying the controller’s action handlermethods we can dispatch the button’s (click) actionto.

3. Click on unveil_full_message_clicked: to allow thebutton to dispatch the click action event to thismethod of our MyWindowController instance.

4. Hit cmd+s to save our changes in Interface Builder.5. Return to Xcode. Make sure we’ve saved all the

changes we’ve made to the files here too via cmd+s.6. Hit the Build & Run button in the toolbar as we’ve

done before.

Congratulations, your very first MacRuby applicationshould now be in working order! Go ahead, click on thebutton to unveil the full message of life!

Download code

14 Working With Mac Programming

Page 15: My Unboxings

BornToBeAlive MacRuby App Example [http://blog.phusion.nl/wp-content/uploads/2010/03/BornTo-BeAlive.zip]

EpilogueFor the sake of brevity — something I know is hard to

believe looking at the volume of this first tutorial — we’veomitted a few steps you’d normally like to take into con-sideration.

For instance, we’ve not connected the window outletof MyWindowController (an outlet it inheritedfromNSWindowController) to our window instance toallow it to manage the window. Connecting this outletoccurs in a similar fashion as was the case with connectingthe label outlet by holding down the right mouse buttonon the MyWindowController instance and dragging it tothe window instance.

Releasing the right mouse button will display a popupmenu outlining the outlets we can connect the window to.Clearly we should select the window outlet here.

We’ve also not yet discussed how we can adhere to theone window per nib file, moving the window object fromour MainMenu.xib to its own nib file and load it in pro-grammatically. As mentioned before, this will requireknowledge of a programming concept called delegateswhich we’ll discuss in our next tutorial. This will also allowus to explain the concept of File’s Owner and so on, whichwill require us to refine some of the techniques we’veexplained up to this point.

For now, go out and celebrate your victory of writingyour very first MacRuby application.

Creating Our Very First Mac Application… 15

Page 16: My Unboxings