Learn Cocoa
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

Layered 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

Variable
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
Editor Window

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

Objects and Class
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.
7

Using 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.
 
Main Xcode Window
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.
9

Create 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 FileNew File from the menu bar.
 
Objective-C Class
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:
 
AppController.m
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.
 
AppController Files
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

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

Add 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.
 
MainMenu.nib
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.
 
Drag AppController.h
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.
 
AppController in Interface Builder
Select AppController in the list and choose ToolsShow 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.
 
13

Create an Instance

Object 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 ClassesInstantiate 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.
 
AppController in Document Window
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.
14

Connect 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.
 
Drag Outlet Connection
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.
 
Activate Outlet 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.
15

Add 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.
 
Resize Text View
Now that we've made some space, we can add the actual button. Open the object palette by choosing ToolsPalettesShow 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.
 
Add Button
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 ToolsShow Inspector. Choose Size from the Inspector dropdown.
 
Set Button Sizing Attributes
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.
16

Connect 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.
 
Drag Action Connection
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.
 
Activate Action Connection
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.
17

Try it Out

Back in Xcode, chose BuildBuild 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.
 
Clear Text View
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.
18

Putting 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.
 
Putting it All Together
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.

Wrap Up

The goal of this tutorial is just to give you a taste of what Cocoa has to offer. Even though we didn't write any code, we ended up with an application which has some very sophisticated text handling. The Xcode project is contained in the following zip file.
LearnCocoaTwo Xcode 2.4 Project (64k)
If you'd like to see more tutorials like this, please make a donation. Please consider the download a thank you gift for your contribution.
Love it? Suggestions? Send feedback on this tutorial.
 
Read between the lines.
Feedback Form
Cocoa Dev Central is a service mark of Tree House Ideas
Site design © 2004-2007 Scott Stevenson | Made with TextMate