Hello. Welcome to the second tutorial all about starting to code in Objective C and Objective J. In this tutorial I go through an example from the Aaron Hillegass book Cocoa Programming For Mac OS X, 2nd Edition, updating it to work in xCode 3.0, and how the same app is written in Cappuccino 0.7 with nib2cib .
Writing The xCode Version
Fire up xCode 3.0 and choose File->New Project. In the window that pops up choose to make a new Mac OS X Cocoa Application like below:
xcode new cocoa application
You will be asked to save it on your Mac. Save it in a sub folder of your User or Documents folder and give the project a name. I’ll call mine RandomAppC. Your new project will open up and xCode will look similar to below.
xCode new project view
If you are not familiar with xCode or similar Integrated Development Environment then you may want to read the Xcode Workspace Guide.
Creating Our Application Controller
We are going to create a new controller object for the random number application. Controllers sit between the view and the model . The controller acts as a link allowing access between views and models. In our simple random number application there isn’t going to a model layer as such as we aren’t dealing with any data. If we wrote an address book program we would be dealing with data objects to represent contacts. Read more about the Model View Controller paradigm and it’s place in Mac OS X programming.
We will focus on how to send messages from our application view to the controller. Let’s create the controller.
In xCode choose File->New File… and create a new Objective-C Class like below:
new objective c class
You will see a window similar to below:
AppController.m
Name the file AppController.m and click finish. AppController will eventually contain two methods that will be called when a user presses a button in the view. For now we will just leave it blank.
Setup Our View
Firstly let’s give our view a reference to AppController. To do this expand the resources folder in the Groups & Files view of xCode and double click on MainMenu.xib to open it in Interface Builder.
Double click MainMenu.xib
Your view of Interface Builder should look something similar to below:
Interface Builder View
Read more about the Interface Builder Workspace.
We are interested in the window with the title MainMenu.xib and the Library floating panel. The Library panel allows you to browse all the available objects you can make use of in your application view. In the search box at the bottom of the Library type in ‘object’. The lower section will show you some information about the NSObject class. NSObject is the basic building block for all objects in Cocoa programming. Drag an NSObject from the Library like so:
Drag and NSObject into MainMenu.xib Window
and drop it into the Document Window window:
Drop NSObject into MainMenu.xib window
It’s name will change to Custom Object. No we will make our newly dropped object into our AppController by setting its class.
- Click once on Custom Object and bring up the inspector
- Choose the little round icon with an i to inspect some basic information for our object
- In the field labelled Class, type AppController
- Press enter to rename our object
Your screen will look similar to below:
Name custom object AppController
Now we will drag some user interface objects. In the object library type button and drag and drop two NSButton objects onto our window like so:
drag and drop buttons
Then search the object library for label and drag a NSTextField onto the application window
Drag a Label
Let’s resize these objects to fit our window:
Resize the buttons and label to fit window
With the two buttons and label selected choose the Size section from the Inspector and setup the Autosizing so that each object can grow wider with our window:
Set Autosizing for Objects
Double click on each button and you will be able to edit their text. Name the top one ‘Seed Random Number Generator’ and the lower one ‘Generate Random Number’. As for the label you can remove it’s text – I left it a label in my demo so you can see it hasn’t gone anywhere.
App Controller needs references to our three interface objects so that when a user clicks a button it can run some code and be able to change the text of our label. Communication in this way happens in two directions – from the interface to App Controller and from App Controller to our interface . Actions are used to fire a method in App Controller after an event in the user interface. Outlets are used to allow App Controller to send messages to the interface. Read more about actions and outlets.
So let’s add some outlets and actions to App Controller:
- Click once on App Controller in the document window and from the Inspector panel choose the Identity section.
- Under the Class Actions section press the plus button to add an Action and type in seedGenerator: as it’s name. Don’t forget the : at the end of the name – interface builder will warn you of this.
- Add another Action called generateNumber
- In the Outlets section click the plus button to add an Outlet to App Controller. Call it myLabel.
Create Actions and Outlets for App Controller
Now we need to link everything together. I never seem to tire of how we do this with drag and drop.
- Hold the Control key, click and drag a connection from the button labelled “Seed Number Generator” to App Controller in the Document Window.
- A small panel will appear when you let go of the mouse allowing you to pick which of the available actions should be used when the button is pressed.
- Do the same for the Generate Number button and choose the generateNumber Action.
- You’ve probably guessed already that in order to connect App Controller to the label on our window we will be dragging the other way. So Control-drag a connection from App Controller in the Document Window to the label and choose the myLabel Outlet from the pop-up inspector.
Control dragging a connection from the Seed button to App Controller
Connect The Generate Button to the seedNumber Action of App Controller
Selecting seedGenerator action and making the connection
Choose the seedGenerator Action of App Controller
With everyting laid out and connections between our App Controller and the interface completed, do a quick File->Save.
We are almost done in interface builder, we just need to update the skeleton class of App Controller with our newly created Actions and Outlets. To do this, in Interface Builder:
- Make sure that App Controller is selected in the Document Window
Choose File->Write Class Files…
Choose File->Write Class Files” /> </li><li><p>In the Save File Dialogue that appears make sure you have ‘Create .h File’ ticked</p><p><img src=
You can safely choose the ‘replace’ option when asked whether to merge or replace the existing files.
We’re finished here so you can quit Interface Builder.
Writing Code
Back in xCode we will now write the code that is run when a button is pressed in out interface. Have a look at the contents of AppController.h and AppController.m. You will notice they have been updated with references to the Outlets and Actions we created in Interface Builder.
AppController.h
#import <Cocoa/Cocoa.h>@interface AppController : NSObject { IBOutlet id myLabel;}- generateNumber:sender;- seedGenerator:sender;@end
AppContoller.m
#import "AppController.h"@implementation AppController- generateNumber:sender {}- seedGenerator:sender {}@end
We need to modify the empty functions in AppController.m so that stuff happens when a user clicks one of our buttons. Make the following changes:
#import "AppController.h"@implementation AppController- generateNumber:sender { //Generate a random number between 1 and 100 inclusiveint generated = % 100) + 1;//Use outlet to tell label to display the number[myLabel setIntValue:generated];}- seedGenerator:sender { //Seed the random number generatorsrandom);[myLabel setStringValue:@"Generator Seeded"];}@end
I won’t go into great detail as to what we’re doing here as the code is commented. The basics are that it’s a good idea to ‘initialise’ the random number generator before using it and we want to generate a new random number everytime the user clicks the Generate Button. The code you can see inside square brackets are messages. You can read more about Objective C syntax.
In xCode you can now click the Build & Go button from the tool bar to run our simple application. Clicking the buttons will alter the label text depeding on the Action performed. So that’s it. A really simple Cocoa App in Objective C. Now, let’s make the same application in Objective J.
Writing the Cappucino Version
We’ll use capp to create a starter application on our desktop. In terminal type the following:
cd ~/Desktop
Followed by:
capp gen -t NibApplication Random
Your terminal will look something like below:
capp gen -t NibApplication Random
On your desktop you should see the new Objective J application folder called Random. Check out the previous tutorial for an overview of the contents of the generated application folder.
Open MainMenu.xib from the Resources folder to edit it in xCode. You can delete the text field and slider from the window.
Drag the same interface elements onto the window, set the label text and lay out the objects pretty much exactly as we did earlier so that your window looks like below:
Window Layout
You may want to make the label a bit wider than default to accomodate our text and set it to centre align.
Select App Controller from the Document window and in the Identity pane of the inspector:
- Create an Action called seedGenerator.
- Create an Action called genertateNumber.
- Don’t forget to add a full colon at the end of each Action name.
- Add an Outlet called myTextField.
Your screen should look roughly like below:
App Controller Actions and Outlets
Make Connections
- Control-click, drag and connect Actions between the user interface buttons and App Controller.
- Control-click, drag and connect the Outlet between App Controller and the text label.
- Remember in our example that Actions flow from interface objects to App Controller, while Outlets flow from App Controller to the interface .
- This should all be familiar now as its exactly what we did in Interface Builder earlier.
Using nib2cib
So we have updated our MainMenu.xib file. Now it needs to be translated by nib2cib. To do this in Terminal type the following command:
nib2cib ~/Desktop/Random/Resources/MainMenu.xib
The above command assumes your skeleton Cappuccino application is in a folder called Random and sitting on your Desktop. nib2cib will do some churning and your Terminal screen should look similar to below:
nib2cib ~/Desktop/Random/Resources/MainMenu.xib
Read more about nib2cib. The result of the above command is that nib2cib will have overwritten the existing MainMenu.cib in the Resources folder. You will have to run this command every time you update MainMenu.xib. We can get on with writing some code now by modifying AppController.j. – open up that file in your text editor and modify the code so it looks like below:
/** AppController.j* Random** Created by You on June 23, 2009.* Copyright 2009, Your Company All rights reserved.*/@import <Foundation/CPObject.j>@implementation AppController : CPObject{ CPWindow theWindow; //this "outlet" is connected automatically by the Cib IBOutlet id myTextField; //Out Outlet to the textfield}- applicationDidFinishLaunching:aNotification{ // This is called when the application is done loading.}- awakeFromCib{ // This is called when the cib is done loading. // You can implement this method on any object instantiated from a Cib. // It's a useful hook for setting up current UI values, and other things. // In this case, we want the window from Cib to become our full browser window //We dont want window to become the full browser window in this case //[theWindow setFullBridge:YES];}- seedGenerator:sender{ //Set the label text [myTextField setStringValue:@"Javascript - Can't seed like Objective C"]; //Make sure the new text stays aligned [myTextField setAlignment:CPCenterTextAlignment];}- generateNumber:sender{ //make a random number and update the text field to show it var randomnumber=Math.floor*11) [myTextField setStringValue:randomnumber] ; [myTextField setAlignment:CPCenterTextAlignment];}@end
The main things we have done above are:
- Added
IBOutlet id myTextField;
This is a reference to the Outlet we created in App Controller in Interface Builder. - Commented out
[theWindow setFullBridge:YES];
We don’t want the window to be full screen in the browser. - Added
- seedGenerator:sender
This is the code run for the seedGenerator: Action we added to App Controller. - Added
- generateNumber:sender
This is the code run for the generateNumber: Action we added to App Controller.
Running the Application
You should now be able to open up index.html inside your Cappuccino application’s folder and see the app in action.
Running The Application
- Download Objective C source code
- Download Objective J source code
Hope that helps
As it might be of interest, I will post up some code of the same application written using Cappuccino 0.6 as I was working without nib2cib and using code to layout my interface objects.
Cheers,
Matt