Professional Documents
Culture Documents
Learn Cocoa II
In the first tutorial in the Learn Cocoa series, we started an application called
CocoaNotepad. Even without any custom code, the app has sophisticated text
handling, thanks to the Cocoa's built-in text functionality.
This tutorial will get you started with writing code. Rather than explain the
theory behind Objective-C, we're just going to dive right in and fill in the gaps
as we go. You might find it helpful to read the C Language Tutorial first, but
this isn't required.
This tutorial has not been updated for Leopard and Xcode 3.1, so Steps 12-18 will
not make sense. I will post an updated version as soon as it is ready. If you want
to try to read through anyway, it is no longer necessary to drag header files to
Interface Builder. IB will find classes automatically.
Stay Focused
The goal here is initial exposure. Don't worry if you can't figure out how all the
pieces fit together yet. Just stay focused on each step and "keep the faith." All
will be explained in time. Code is the engine of an application. The user sees the
interface, but that interface only shows up on the screen and responds to user
actions because of the underlying code.
Being a Cocoa programmer means taking a concept and figuring out how it can be
expressed in code. In most cases, code for a Cocoa application is written in
Objective-C.
If you're new to programming, you might wonder what code is. It's simply a
collection of instructions. In fact, writing code for a computer is similar to
writing instructions for people. For example, take a look at the following driving
directions.
This table shows how the structure of the code can be broken down into smaller
pieces:
Thing Action Detail
car enterFreeway: I-280 South
car exitFreewayAtRamp: De Anza
car performUTurnAtStreet: Mariani Avenue
car turnRightAtStreet: 1 Infinite Loop
There are three parts to each line of code in this example: an object, a message,
and an input value. Not all Objective-C code is exactly like this. Some actions
have no input, for example.
2
Variables
Most of this tutorial focuses on practical examples instead of theory, but there
are a few ideas that need an explanation before we dive in.
A variable is simply a label for a container. It holds a value, and the value can
change at any time. A variable can hold any type of data, such as text, images or
numbers.
For example, a variable called milesPerGallon might have an initial value of 22.
That same variable could be changed to another value. An example of that is shown
here:
milesPerGallon = 22;
milesPerGallon = 18;
Types 2.1
In Objective-C, variables must be declared before they are used. Here are some
simple examples:
int milesPerGallon;
id userName;
id currentPhoto;
Each of these lines declares a new variable, prefixed by a type. The type states
what kind of data the variable can hold. The variable milesPerGallon is declared
as an int, which is an integer number.
The id type can hold any object. If you don't know what an object is, don't get
stuck on it now. We'll learn more about that soon.
There are many variable types defined by Cocoa itself, and you can create your
own. For this tutorial, we're only going to use the generic id type.
Assignments 2.2
id order;
order = @"Four thousand lattes, please.";
The @ symbol in front of the text is an Objective-C convention, which we're not
ready to get into the details of just yet.
3
Methods
Methods are a list of instructions for the computer to perform. The list is given
a name, so that the same list of instructions can be performed over and over.
For example, the list of instructions from the first section could be grouped as
one method called driveToWork, shown below:
- driveToWork
{
[self enterFreeway: @"I-280 South"];
[self exitFreewayAtRamp: @"De Anza"];
[self performUTurnAtStreet: @"Mariani Ave"];
[self turnRightAtStreet: @"1 Infinite Loop"];
}
The code to call the method in Objective-C looks like this:
[car driveToWork];
Calling the driveToWork method is essentially the equivalent of calling all of
those other lines of code individually. It's not just to save space. If you need
to change the contents of a method later, you can do it in just one place.
Methods can have both input and output, though neither is required. Output from
one method can be used as input for another. Here are some simplistic examples:
// no output or input
[car driveToWork];
// providing input
[car enterFreeway: 280];
[car setSpeed: 68];
[car setRadio: 105.3];
// multiple input
[car enterFreeway:280 atSpeed:68];
[car setRadio:105.3 withVolume:21];
// getting output
speed = [car currentSpeed];
distance = [car totalDistanceTraveled];
destination = [car targetDestination];
When writing code, things that may seem trivial can actually be very important.
Even leaving out a single character or putting particular parts of code in the
wrong order can cause errors.
When Xcode sees incorrect code, it can typically only display an error because it
doesn't know what your intentions are. It's up to you, as the programmer, to fix
the error. It's important to understand some basic formatting rules.
The spacing between words in code might seem strange. In English, an instruction
to exit the freeway looks like this:
exit freeway at the De Anza ramp
In Objective-C, it looks like this:
[object method:@"input"];
If you leave it out, you'll get error messages. Some instructions span multiple
lines. In those cases, you put a semicolon at the end of the final line only:
Simplified
The examples in this section are designed to explain concepts more than specific
rules. They use a less formal structure than what you'd find in most Cocoa code.
Many things in Cocoa are presented to developers as classes. For example, a number
is represented by the class NSNumber. A class describes either a real-world object
or an abstract concept by giving it specific attributes and methods.
There are whole books on the theories of classes and their design, but we don't
need all of that to get started. We're going to focus on practical basics.
To write an application which manages photos, you might start by creating a Photo
class. Each photo has variables which define unique attributes about the item,
such as the ones listed below:
Photo
- Width
- Height
- Date
- Title
These variables are called instance variables, or simply attributes. Here's a
photo Objective-C class with the attributes from above:
The next several lines list the attributes of a Photo, each one prefixed with id.
This is how Objective-C knows that these are attributes. Not all attributes are
id, but we can do it for simplicity here. The class definition ends with @end on
the final line.
Photo
- Desaturate
- Display
- Delete
We can express these as methods in our Photo class:
This pattern of starting with basic class name, then adding attributes and methods
is the basis for all object-oriented programming.
6
Objects
Consider the schematics for an apartment complex. You can't live in the
schematics. Somebody has to take the schematics and create an actual building from
them. In fact, you can create many instances of the building in different
locations using the same set of plans.
Below is an example of how to make two photo objects in Objective-C. Again, keep
in mind that this code is simplified to focus on the concepts rather than the
rules.
[photo1 desaturate];
[photo1 display];
[photo1 delete];
[photo2 desaturate];
[photo2 display];
Since these are two separate photo objects, the actions performed on each are
specific to that object. In other words, if we use -desaturate on photo1, the
photo2 object is unaffected. In fact, we can delete photo1 without having any
impact on photo2 at all.
Now, to be fair, the above code wouldn't work because we haven't defined what each
of these methods actually does. That would be fairly complicated at this point, so
we're going to move onto other basic concepts.
7Using Xcode
Xcode is what most Cocoa programmers use to write code. There are other options
and some of them very good. To keep things simple, though, we're going to focus on
Xcode.
For most projects, your code will be spread across dozens of files. Large projects
have hundreds of files or more.
When you compile the project, Xcode combines the files into a single double-
clickable application, along with supporting media, such as images and help files.
Xcode might seem overwhelming, but don't get discouraged. Even expert developers
don't know what every single button, checkbox, and menu item does. You can start
by learning about the parts that are relevant to what you want to do.
9Create a New Class
Re-open the CocoaNotepad project from the first tutorial. Click on the Classes
group on the left side of the window then and choose File → New File from the menu
bar.
Select Objective-C class from the Cocoa group, then click Next. Many of the names
are similar, so choose carefully. You'll be asked to choose a file name for the
class:
Type AppController.m for the file name, and leave everything else at the default
settings. Click Finish to add the new file to the project. You should now see them
listed in the Classes folder.
Now that these files are part of the CocoaNotepad target, the code from them will
be compiled into the application when you choose Build and Run. Of course, the
class doesn't do anything yet.
10
The Header File
A header file provides an overview of a class. It lists the variables and methods
that the class offers, but doesn't contain the details of how those things work.
It's somewhat like a table of contents.
First, we're going to add a variable. In fact, it's a special kind of variable,
called an IBOutlet, which is short for Interface Builder Outlet. This variable
holds a connection to a user interface item, such as a text field. The connection
is wired up visually using Interface Builder.
With that connection in place, you can send instructions to the user interface
item. For example, you could enable or disable it, move it, or change its
appearance. You can also use IBOutlets for objects which don't appear onscreen.
// AppController.h
// CocoaNotepad
#import <Cocoa/Cocoa.h>
The lines that start with a double slash are comments, and have no affect on how
the application works. They're just there as notes to yourself and anyone else who
may see your code.
#import "AppController.h"
@implementation AppController
}
@end
Note that the method does not end with a semicolon. Because this is the
implementation of the method, the method name is followed by a pair of brackets.
Add the following code between the brackets:
In this case, we're calling the setString: method, which changes the contents of
the text field. The input for this method is @" ", which amounts to a single blank
space. In context, it should look like this:
#import "AppController.h"
@implementation AppController
So let's wire everything up in the user interface first, then try it out in a
working application. You can always come back and look at the details of this code
more closely. For now, save AppController.m and close it.
12Add Header to NIB
In order to use the new AppController class in the user interface, we need to add
it to the MainMenu.nib file which we created in the first tutorial. Unfold the
Resources folder in the main Xcode window and double-click MainMenu.nib to open it
in Interface Builder.
Now drag AppController.h from the Xcode window and drop it on the Interface
Builder document window. The document window will then switch to the Classes tab.
Once you drop the header file, the document window will switch to the Classes tab.
Click on the list view toggle control at the left side of the document, just below
the tabs. It looks similar to the list view toggle in the Finder.
Select AppController in the list and choose Tools → Show Inspector to bring up the
inspector window. Make sure Attributes is selected from the inspector dropdown.
You should now see Outlets and Actions listed in the inspector window. Click on
the Outlets tab, and you should see textView listed. If you click the Actions tab,
you should also see the clearText: method which you created.
13Create an Instance
Now that the AppController class is part of the NIB file, we need to make an
instance. Make sure the AppController class is still selected in the document
window and choose Classes → Instantiate AppController from the menu bar.
The document window will switch to the Instances tab, and you'll see a blue cube
labeled AppController. This is your object instance.
The tiny orange exclamation mark icon tells you that there is at least one
unconnected outlet. So let's connect it.
14Connect the Outlet
Double-click the Window icon to open your application window. Hold down the
Control key and drag a line from AppController to the text view in the application
window. You can release the Control key as soon as you begin the drag.
Make sure you're starting the drag at AppController and moving towards the text
view, not the other way around.
When you release the mouse button, the Inspector window will pop up with the
Connections section displayed. The textView outlet should be selected. Click
Connect to activate the connection.
Once a connection is active, a silver dot appears next to the outlet name. The
Destination column now reads NSTextView, which is the class of the object that the
outlet is connected to. Now that this connection is in place, we can call methods
on the text view.
15Add a Button
We're going to add a button which calls the clearText: method. First, let's make
some room. Resize the text view by click on it and dragging the bottom handle up a
bit.
Now that we've made some space, we can add the actual button. Open the object
palette by choosing Tools → Palettes → Show Palette from the menu bar.
Click on the Cocoa-Controls toolbar item in the palette, which is usually the
second one from the left. There's a control simply labeled Button. If you hover
the mouse pointer over it, a tooltip reveals its class name — NSButton.
Drag the button over to the application window and drop it in the space you've
made below the text view.
Change the button title to "Clear Text" by double-clicking it, then press Return
when you're done editing it.
Make sure the button is still selected and open the Inspector with Tools → Show
Inspector. Choose Size from the Inspector dropdown.
In the Autosizing box, click the top and left segments of the outer rectangle.
This tells Interface Builder to allow the outside of the button to grow and shrink
with the window, keeping the button itself pinned to the lower right.
You could create an IBOutlet for the button, but there's no need to do that in
this case since we don't need to call any methods on it.
16Connect the Button
Now we need to wire up the button to the clearText: method. Hold down the Control
key and drag a connection from the button to AppController. Remember you can
release the Control key as soon as you begin the drag.
In this case, though, you're starting the drag at the button and moving towards
AppController — the opposite of when we were connecting an outlet.
When you release the mouse button, the Inspector window will pop up with a list of
possible action to connect the button to. In some cases, you may have to click the
Target/Action tab to see the available actions.
Make sure clearText: is selected then click Connect. This method will be called
every time the button is clicked.
When you're done, save the file and switch back to Xcode.
17Try it Out
Back in Xcode, chose Build → Build and Run to try the application out. You should
now be able to type whatever text you want in the application and clear it with
the Clear Text button.
This may seem like a lot of work for such a simple feature, but a lot of this was
just basic set-up and fundamental concepts. Adding additional code is now much
easier.
18Putting it All Together
Now that you've seen it all running, you might be curious about how the pieces fit
together. There are three basic pieces: the button, the AppController instance,
and the text view.
When the user clicks the button, it sends clearText: action to the AppController,
which uses [textView setString:@" "] to clear the text view. This same process is
repeated every time the button is clicked.
You might wonder why the button doesn't clear the text view itself. In other
words, why involve AppController at all?
In CocoaNotepad, the View objects are the button and the text view. The controller
is AppController. We don't create model objects directly in this tutorial, but you
can think of them as the raw data, such as the text in the text view.
By separating the View and Model objects, and using AppController to communicate
between the two, it's easier to add new data or new views without completely
rewriting the application.