You are on page 1of 11

Cocoa Dev Central

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 is written and illustrated by Scott Stevenson

YOU MUST READ THIS BEFORE CONTINUING

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.

Copyright © 2006 Scott Stevenson


1
Thinking in Code

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.

Enter I-280 South


Exit at De Anza ramp
Make a u-turn at Mariani Avenue
Turn right into 1 Infinite Loop
If this was Objective-C code, it might look more like the example below:

[car enterFreeway: @"I-280 South"];


[car exitFreewayAtRamp: @"De Anza"];
[car performUTurnAtStreet: @"Mariani Ave"];
[car turnRightAtStreet: @"1 Infinite Loop"];
When you write instructions for a person, you can leave certain details out
because they're obvious. Programming languages are more strict. You must be
explicit and consistent.

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

An assignment is a line of code that assigns a value to a variable, just like in


algebra. For example, here we assign a line of text to a variable called order.

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];

// multiple input with output


travelTime = [car estimatedTravelTimeAtSpeed:68 duringRushHour:NO];
We use assignments to store the method output in variables. For example, the
currentSpeed method returns a value which we assign to the speed variable.
4
Writing Code

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.

Word Spacing 4.1

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:

[car exitFreewayAtRamp:@"De Anza"];


It's easier for the computer to understand the code if certain words are grouped
together. Not all methods are spaced exactly like this. You'll learn more about
this as you go.

End With a Semicolon 4.2

In English, a period (.) marks the end of a sentence. In Objective-C, each


instruction ends with a semicolon.

[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:

travelTime = [car travelTimeAtSpeed: speed


duringRushHour: NO];
You can put these multiple-line instructions on one line if you like. Formatting
them across multiple lines is just meant to make the code easier to read.
5
Classes

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.

Adding Attributes 5.1

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:

@interface Photo : NSObject


{
id width;
id height;
id date;
id title;
}
@end
The @interface statement begins the Photo class definition. It inherits from
NSObject, which means it has all of the same functionality as that class. Again,
we're not going to get too stuck on the details of what that means yet.

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.

Adding Methods 5.2

In addition to attributes which store information, classes also have methods,


which perform actions. For example, you might want to do the follow things with a
photo:

Photo
- Desaturate
- Display
- Delete
We can express these as methods in our Photo class:

@interface Photo : NSObject


{
id width;
id height;
id date;
id title;
}
- desaturate;
- display;
- delete;
@end
The methods are declared after the brackets, but before the @end statement. Each
instance method is prefixed with a single dash. These methods don't do anything
yet, we've just stated that they exist.

This pattern of starting with basic class name, then adding attributes and methods
is the basis for all object-oriented programming.
6
Objects

A class is just an abstract description. In most cases, you need to make an


instance of the class to do useful things with it. An instance of a class is
called an object.

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.

id photo1 = [[Photo alloc] init];


id photo2 = [[Photo alloc] init];
Both photo1 and photo2 are objects. Specifically, they're instances of the Photo
class. Any attributes we add to the Photo class will become available to these
objects. Let's see how we would go about using the methods we declared in the
Photo class:

[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.

Xcode's editor is specifically designed for programming, so it has some


significant advantages over general text editors. Xcode is more than a text
editor, though. It's your "base of operations" for writing Mac software.

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.

Add an Outlet 10.1

Double-click on AppController.h to open it in an editor window. Make sure you open


AppController.h, not AppController.m. Edit the contents of the file to look like
this:

// AppController.h
// CocoaNotepad

#import <Cocoa/Cocoa.h>

@interface AppController : NSObject {


IBOutlet id textView;
}
@end
Most of the text was probably filled in by Xcode. In most cases, you should only
have to add the IBOutlet line. This line says that AppController will have a
connection to something called textView. It's literally an outlet — you plug the
text view into it.

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.

Add a Method 10.2

Next, we're going to add a method. Remember, a method is a list of instructions


which are grouped together. Change the contents of the file to look like this (the
comments are not shown):

@interface AppController : NSObject {


IBOutlet id textView;
}
- (IBAction) clearText: sender;
@end
An IBAction is a special kind of method which, much like an outlet, can be wired
up in Interface Builder. This method will be used with a button.
11
The Implementation File

Double click AppController.m, which is the implementation file. The implementation


file contains all of the details about how the class behaves. It's the counterpart
to the header file.
Change the file to look like the code below, adding the clearText method:

#import "AppController.h"

@implementation AppController

- (IBAction) clearText: sender


{

}
@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:

[textView setString: @" "];


The textView outlet will be connected to an object. Specifically, an NSTextView
object. Since it's an object, we can call methods on it, just like we did with
photo1 and photo2 earlier.

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

- (IBAction) clearText: sender


{
[textView setString: @" "];
}
@end
At this point, you might be a bit confused. It's okay, that's normal. We could try
to explain how all of this works, but the explanations will make much more sense
after you see the final result in action.

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.

Conceptually, this is similar to doing [[AppController alloc] init] in code, but


creating an instance in Interface Builder allows us to wire up connections
visually.

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?

Model View Controller


In Cocoa, classes have specific responsibilities, which makes it easier to create
and change complex applications. This design is called Model-View-Controller.

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.

You might also like