July 01 Cover
Volume Number: 17 (2001)
Issue Number: 07
Column Tag: Cocoa
Write a Cocoa Application with One Line of Code!
by David A. Trevas
With the advent of Mac OS X, there is whole new way to conceive and build Macintosh programs called Cocoa. While the Classic and Carbon environments provide a link to the single-digit Mac operating systems, Cocoa is for OS X only and, as such, takes maximum advantage of the technical and visual improvements of the new system. The use of the elegant Objective-C language makes the concepts of object-oriented programming very clear. No matter how elegant the language is, diving too quickly into writing many lines of code in an introductory program can discourage many of the newcomers to Cocoa. The reader should know how the program's author chose each line of code. It is this thought process that the readers need to learn. I believe that an introductory article should show you around and demonstrate how basic things work to give you the confidence and the knowledge to go to higher levels. To give you a good welcome to Cocoa, I have chosen an excellent number of lines of code for you to write: one. I promise that you're going to be surprised what you can do with just one line of code!
This article is intended to introduce you to the structure of a Cocoa project, the workflow involved in building one, and the techniques and terminology of Cocoa programming in general. I am assuming nothing about your knowledge of programming, but I am assuming that you have used some Macintosh applications and have used buttons, menus, text fields and the like. You will need perseverance–a trial-and-error attitude–since both of us will be very lucky if everything goes exactly right the first time, even if you follow the instructions carefully. You may have to try something a few times or even backtrack a little to get things right.
Create a New Project
If you don't already have ProjectBuilder, go to the Apple Developer Connection web site and join. "How much is this going to set me back?," you grumble, but the good news is that the lowest membership level that can access the Mac OS X Developer Tools is FREE! You can become an Online Member for zilch and go download Mac OS X Developer Tools including ProjectBuilder and InterfaceBuilder.
1. Please, open ProjectBuilder and start a new Cocoa Application.
I'm sorry, but I'm not going to be able to write "please" and "thank you" anymore when I ask you to do things. Alas, it's the ancient conflict: Barney vs. Word Count. Go to File > New Project..., a dialog asking you which kind of project you want to use appears. If the little blue triangle, called a "disclosure triangle," next to the word Applications is pointing to the right, click on it once to expose the subcategories. Click on Cocoa Application.
You will then be prompted to put a name in the upper text box, you can use "MyFirstProject" if something more brilliant doesn't come to mind. Notice that you don't need to put an extension (dot-something) because the title is that of a folder created by ProjectBuilder. You may use the Set... button to put this folder in a location other than the one it is proposing in the second text box. The Set... button causes a navigation panel to appear and once you've highlighted the folder into which you want your project folder to go, click on the Open button. Click Finish in the naming dialog.
Figure 1. A Cocoa Application in ProjectBuilder.
Your project then opens up and you'll see a column on the left with five headings each flanked on its left by right-pointing disclosure triangles (see Figure 1). The first is Classes, it is where the code for the building blocks of the project should go. The second heading is Other Sources and it contains main.m, which is where everything really happens once the program starts to run. Happily, you don't need to touch this file for this project and you may get through many more projects before you become concerned with the details of its function. The third heading, Resources, is the one in which you will be working mostly. It contains MainMenu.nib which is the basis of the user interface we will be creating. The fourth heading is Frameworks and under the subheading Linked Frameworks resides Cocoa.framework which connects us with the years of work done at NeXT and Apple that makes our lives easier. Finally, the last heading called Products contains MyFirstProject.app which is end result of our labors, the executable file (Psst! Most normal users will see this as a single file, when, in fact it is really a package containing several different files. Just thought you'd like to know!)
2. Double-click the MainMenu.nib to open InterfaceBuilder.
The first thing to notice is that by double-clicking a file in ProjectBuilder, you open up InterfaceBuilder. The two are actually separate programs (applications) that are conveniently aware of one another. The next thing you will notice, or be overwhelmed by, is that your simple double-click has caused a great many things to happen. Overlaying you ProjectBuilder window are now four windows entitled: "MainMenu.nib...", "Cocoa - (something) Palette", "MainMenu - MainMenu", and "My Window" You might find it a little neater to go to the InterfaceBuilder menu and Hide Others to reduce the clutter.
A little side note: Cocoa is based on work done at NeXT which Apple bought in 1997. You will see that heritage show through time and again. For instance, a nib file is an acronym for NeXT Interface Builder (and I'll bet that it is not merely coincidental that a nib is the tip of a pen). You will also see the prefix "NS" on all of the objects which stands for NeXTStep.
Design the User Interface
From your perspective as one who uses programs, you may recognize the things you see in the palette as the places you put data or ask for something to happen or see the results of the program's "thinking." Each element is an "object" (a concept I will explain later) that has already been written and this frees you from a lot of code-writing. "A lot of code-writing" often means "tedium with a big probability of making mistakes."
Figure 2. The Views Palette
Click the icons on the toolbar at the top of the "Cocoa - (something) Palette" window until you get to the one that says "Cocoa - Views Palette" and looks like Figure 2. A little time-out here is necessary to clarify some of this AppKit jargon. First, what the heck is AppKit? Cocoa has two main aspects: Foundation takes care of things related to the fundamentals of programming, while AppKit (short for Application Kit) helps you with things pertaining to applications such as windows, buttons and menus. Now, what's the deal with views? As one who works a lot with CAD, I normally associate views to things like Front View, side View, etc., but that isn't correct here. Loosely speaking, if you substitute "visible thing" for "view", you'll be good to go at this point. Among these visible things are those items referred to as user interface elements, controls or even gadgets.
3. Add user interface elements to "My Window".
Here you will add several of the typical Macintosh user interface elements, termed views by InterfaceBuilder. If you complete this entire section, you should end up with something like Figure 3.
Figure 3. Window Full of Views (Visible Things).
Text Fields. Click and hold the mouse over the white box called the text box (or text field). Drag it into the window entitled "My Window" and release it. After you release the text field in the window, little bubbles appear around its perimeter. Grab the middle one on the right-hand edge and pull it toward the other edge of the window and you now have a much wider box.
Go to File>Save (or type Cmd-S) to save the nib file. Try to get in a habit of saving often - I have found InterfaceBuilder to be, charitably speaking, a bit quirky. Better save than sorry!
Buttons. Drag the Button from the palette to My Window. Double-click on the word "Button" to edit it. This theme of double-clicking on words to edit them is fairly consistent in InterfaceBuilder. I put the words "Panic Button" there and appreciated the automatic resizing. Did you?
At this point, you have a choice: add more things and explore the subtleties of each or get in the Express Lane and jump to the next section. For the rest of this section, in fact, you can skip down without any long-term adverse effects, assuming that you come back later and do this exercise completely.
Check Boxes. Another easy view (visible thing) is the check box, which is called "Switch" on the palette. Drag a switch from the palette and put it in the window. Since we're talking about checks, I label the check box "Duplicate" to remind you of the option of having instant copies so you don't have to balance your checkbook in front of me in the grocery store line. Thanks for bringing your 23 items to the express line, too! Did you remember how to edit the text? That's right, double-click on the word "Switch."
Radio Buttons. Turning it up a notch, we will move on to radio buttons and because their behavior is that "one and only one" is activated, they only make sense when more than one is present. Drag a Radio into the window and notice that you get two for the price of one. Now, you say, "Your window has three radio buttons, but I only have two and if I repeat the step I'll have four buttons, which is still not three, so, what the heck?!" Ah, yes, I remember the feeling well and I must confess, I didn't use "heck". But the I found Alt-dragging (a. k. a. Option-dragging) and all was well. Click once in the midst of the radio buttons and a box with little dots around it appears. Hold down the Option key and grab the bottom center dot and drag it down–perfectly aligned radio buttons materialize like magic. By the way, had you selected the lower-right dot and dragged down and to the right, you'd get rows and columns of radio buttons.
Radio 1, Radio 2 and Radio 3 are not exactly names that apply for every situation so now you need to edit the words. Double-click on "Radio 1" and sigh as your editing ability hasn't returned. Time to call the Inspector! Click once in the empty area of "My Window" to undo this last selection. Press Cmd-Shift-I (or go to Tools>Inspector, but you will probably be glad to learn the keyboard shortcut) and look at the new window that appears, the title bar tells you what kind of object you are inspecting. Push it off to the right a little so you have a better view of the radio buttons. Click once on the buttons and a frame surrounding all three should appear. The title bar tells you that you are looking at an NSMatrix, that is, an array of objects. Double-click on Radio 1 again and now the Inspector title bar says that your are looking at an NSButtonCell. Double-click now on the button cell and you can edit it. I called them "AM", "FM" and "SW" for short wave since these could be buttons on a radio. If you double-clicked on the Matrix and Keanu Reeves and Lawrence Fishburne popped out and started kung-fu fighting, you clicked the wrong Matrix. The difference between an NSButton and NSButtonCell is not important for this project, but feel free to poke around in the AppKit documentation to find out more. Sorry, no extra credit.
Pop-Up Menus. These are straightforward, but things get a little trickier for pull-downs. Drag a pop-up menu from the palette to "My Window". Double-click over the phrase, "Item 1", and you will notice that three items appear. What if you want more? Keep in mind that this is a menu and what you will learn in the next section about menus will apply. Double-click again over an item's words to be able to edit them. I called my items, "Corn", "Toast" and "Weasel" for things that go "pop."
Pull-Down Menus. The way I found to create a pull-down menu is to start its life as a pop-up. Again, drag a pop-up menu from the palette to "My Window". Double-click over the phrase, "Item 1", and double-click it again to be able to edit it. In a pull-down menu, the first item is not a choice but the permanent title of the menu, just like a menu title from the menu bar. I'm calling this menu "Pulling Forces" and hitting Return. Call up the Inspector (Cmd-Shift-I or Tools>Inspector...) and click once anywhere in the empty space of the window and return to the pop-up you want to change and click it. The Inspector's title bar should read "NSPopUpButton Inspector" and if it is not already showing, choose "Attributes" from the pop-up just below the title. Simply choose the PullDown radio button to do the switch. Now, when you double-click over "Pulling Forces", you will see Items 2 and 3 in a box slightly below the button itself. Double-click on Item 2 and call it "Gravity" and change Item 3 to "Magnetism".
If you've done this kind of work before, you will notice some things missing in the Views Palette. That's why there is a More Views Palette (see Figure 4). From this palette, we will take two elements: a slider and a combo box.
Figure 4. The More Views Palette.
Sliders. While you see four different sliders, they are all the same except that their attributes are set differently. Choose the one you like best and drag it on to "My Window." You can play with the attributes if you like. Of course, how am I going to stop you if I didn't want you to play with them?
Combo Boxes. Finally, drag a combo box from the More Views palette into "My Window." It is a somewhat a combination of a text box and a pop-up menu.
Figure 5. NSComboBox Inspector.
To put in your items, call up the Inspector (Cmd-Shift-I, or Tools>Inspector, if you insist) and choose "Attributes" if you are not there already. The entry box is that little one at the bottom (as seen in Figure 5). Click in that box and type the text you want and hit Return. Repeat as often as you wish. I entered "Peanut Butter & Jelly" , "Macaroni & Cheese", and "Soup & Salad." I also changed the "Number of visible items" to three.
Feature: The Macintosh Human Interface Guidelines.
We're plopping the views (visible things) somewhat chaotically in the window and we'll be asking some of them to behave in ways that are not normal in Mac programs. This is O.K. since we're just throwing together a little intro here. However, if you plan to create programs for wider consumption, there is some must-read material at the Apple web site that you just, uh, must read. If you love Macs, I'll bet that one big reason you do is the Macintosh Human Interface Guidelines. This book details the proper usage and placement of each element of the user interface and the fundamental Mac philosophy with regard to the interaction between person and computer. Since these guidelines have been widely available for years, software developers have been able to create programs with such consistent interfaces that learning to use them is much easier than on other platforms. So go download Macintosh Human Interface Guidelines and don't forget Mac OS 8 Human Interface Guidelines and Aqua Human Interface Guidelines that add guidelines for elements that were introduced in Mac OS 8 and Mac OS X, respectively.
4. Add a new menu title and items to that new menu.
Go to the Menus Palette. You'll notice that pre-defined menus for some of the most widely used menus are there. Then, there are three other items you use for creating your own menus and modifying them and the pre-defined ones: Submenu, Item and an apparently blank one.
Figure 6. The Menu Palette.
"Submenu" means "menu title or menu item with lower level items"
"Item" is a menu item that doesn't have sub-items. Items are the only things on menus that interact with the rest of the project.
The blank one is a divider (not a uniter), also known as a separator. They simply provide a space so that you can group menu items into logical and visually appealing units.
When you complete this section your menus should appear like the ones in Figure 7.
Figure 7. The Menu System of the Project.
Separators. The easiest thing to do is to place a separator. First, look at the window entitled "Main Menu - Main Menu" which might not sound like a weird name if you live on Bora Bora, eat couscous or have beri-beri. It represents the menu system of your project. Click once on the Edit menu of "Main Menu - Main Menu" to see a pre-written menu that has some of your trusty old friends like Cut and Paste on it. Meanwhile, back at the palettes, click on the menu palette icon at the far left of the toolbar. Click on the empty blue box at the bottom and drag it toward the edit menu. Notice that you are dragging a blue rectangle attached to the arrow representing the position of your mouse. It seems that InterfaceBuilder considers the tip of the arrow as your intention when moving something that takes up a lot of real estate. Move the tip of the arrow, therefore, to a point below the lower half of the words Select All and let go. A space should open up just below the Select All item. If it doesn't, hit the Delete key and try again.
Items. Once you've done this, you can put items in your own new section of the Edit menu. This time drag an "Item" from the palette to the Edit menu and drop it below the separator. To edit the text, we do what? Double-click on the word "Item" and type "Wipe Out" as if you wanted a command to nuke your current work so you can start over again.
If you are cruising through this exercise in the express lane, you can jump to the next step.
Command-Key Equivalents. Once you have become familiar with a program and tire of reaching for the menu bar for doing routine operations, you learn the command-key equivalents, also known as keyboard shortcuts. The key with the Apple and the propeller (or clover or flower) on it is called the Command Key (abbreviated Cmd in documents that don't have a font that has the symbol.) You know the typical command-key equivalents: Cmd-N for New..., Cmd-P for Print..., Cmd-X for Cut, Cmd-C for Copy, and so forth. To create a command-key equivalent for "Wipe Out", move your mouse to the Wipe Out item in the Edit menu and then to the far right side of that item, directly under Cmd-X and Cmd-C. Double-click and a little white outline rectangle that might hold one character appears. Here is where you type the keys that go with Command Key symbol (i.e., don't use the Command Key) which usually is a letter. Type "W" and nothing happens, why? Because, if you look at the File menu, you will see that Close is already assigned to Cmd-W. InterfaceBuilder automatically makes sure that you do not reuse keys or key combinations (of course, it would be nice to get a warning and then prompted to try something else.) Repeat the step to get the outline rectangle to appear and this time hold down the Shift key and type "W". You see that the characters Shift (an upward-pointing arrow), Cmd, W to the right of "Wipe Out" are now the command-key equivalent. Now you are ready to make your own menu.
Submenus. Drag a Submenu from the palette to the Main Menu bar and place your cursor arrow between Edit and Window. Double-click the newly placed text and type in "Dinner". Click once on Dinner and underneath a single Item appears. Double-click on it and call it "Chicken." Now comes the most excruciating part of the project (at least it was for me–you may benefit from my ordeal.) To make the first command-key equivalent in a menu takes a keen eye and a steady hand. Ever so gently, place the tip of your cursor on the right-hand edge of the "n" of the word "Chicken," and double-click. If you got that rectangular outline to pop up on the first try, you definitely benefited from my tribulation. Use "K" for the keyboard shortcut. Is it just me, or doesn't it seem that the ability to create a keyboard shortcut should be available in the NSMenuItem Inspector window?
Now, for the more familiar use of submenu: a menu item with a right-pointing triangle that guides you to more choices. Drag a Submenu to the spot just below "Chicken" in the Dinner menu. Double-click it and call it "Fish." Click once on "Fish" to see the item and rename it "Tuna." Now, with you newly-found skill at placing the first keyboard shortcut on a menu, double-click at the right edge of the "a" in "Tuna". In that outline, hold down the Option key and type "T" and you will see that the keyboard shortcut for Tuna is weird symbol for Option, Cmd, T. (If any of you knows where that weird symbol for Option comes from, please tell me.)
Hopefully, you are now in tuna with the menu system and are not floundering about. If you are up to it, add an item below Tuna called "Flounder" and set its keyboard shortcut to Option-F (of course, the Cmd adds itself automatically.) And why not just one more for the halibut? Add an item and call it "Halibut" and set its shortcut to Option-H.
Make a New Object in InterfaceBuilder.
Feature: Objective-C and Object-Oriented Programming.
Before we can continue, we need to discuss a few concepts and terms. Objective-C is a language that extends the C language by making the object the central unit of programming. It is the original language of Cocoa and its predecessors, although current Cocoa programmers have the option to do their work in Java. If you know C, you should be able to pick it up quickly by reading Object-Oriented Programming and the Objective-C Language which available freely from the Apple web site. If you don't know C, you can learn it later and just follow the code-writing parts as written. As one who has struggled several times to really "get" C++, I found that Objective-C provided a much better way to understand object-oriented concepts and yielded code that was much more readable (after I got used to the square brackets and the colons).
Cocoa applications are generally conceived as a network of objects. You can think of objects as people. Different objects know different facts (data) and possess different skills (methods). Like people, they can communicate with one another. Using messages, one object can ask another for information or to do something. They can also talk to themselves, but that is not a sign of mental illness for objects.
The descriptions of an object's knowledge and skills is contained in its class, also known as a factory in Objective-C. An object is an instance of a class (or the product created by a factory.)
A class can have children and pass along its data and methods to them. A child class can add more data and methods and alter the methods it inherited. The child class' methods can deviate from its parent's completely, slightly or not at all.
Often one finds a class that somewhat does what one wants and uses that as a basis to create an class that does exactly what one wants. Almost every class in a Cocoa project inherits (either directly or after a few generations) from a fundamental class called NSObject. NSObject handles things like object identification and memory management, so a great deal of knowledge and courage are required if you want to avoid it.
In this way of writing programs, your concept of data needs to expand from what you may have learned from earlier languages. As before, there is some data that lives within the object. For example, a Rectangle object may have data members called "Height" and "Width". In Objective-C, however, a common piece of data is just the address (or location) of another object. We say that this piece of data "points to" the other object. To return to the metaphor of people, it brings to mind the saying, "It's not what you know, it's who you know." Witness the ongoing value people put on their address storage systems from little black books to Rolodexes to organizers to Palm Pilots and you will see why there is power not only in knowing things and having skills, but also in knowing where to find others who have knowledge and skills that you don't.
5. Create a subclass of NSObject as the Application Controller.
We're going to need an object that acts as a traffic cop to direct all of the input that comes from our buttons, sliders, etc. and send some kind of output to the text field. We call this kind of object a "controller." We aren't yet aware of a good starting point for a controller, so we create the blueprint (or class) of a controller that inherits from NSObject. Another way to say it is that the controller should be a subclass of NSObject.
Figure 8. MainMenu.nib Window with Classes Tab Selected.
In the MainMenu.nib window, click on the tab called Classes and your screen should show you something very much like Figure 8. Scroll to the very top and find NSObject. Click the NSObject once and go to the Classes menu located on InterfaceBuilder's menu bar at the top of the screen. Select Subclass and a new class called "MyObject" appears, ready to be edited. Change the name to "MyController." (Using names beginning with "my" is an old cliche for introductory programming exercises. It is supposed to indicate the separation of the words that you must use exactly as specified by the language from the those with which you have some freedom. You may indulge my penchant for corniness or call this object something else if you want.)
6. Add an outlet to the text field.
An outlet can be thought of as the place where data goes when it is ready to leave the controller. To create one, click on MyController if it is not already highlighted. Go to the Classes menu at the top of the screen and choose Add Outlet. Call the outlet "theTextField."
Notice the two icons in the right-hand column. The first one with the two vertical lines is supposed to remind you of an electrical outlet. Since you added the outlet, the number 1 appears just to the outlet symbol's left. And, by the way, this is one of those pieces of data that is only the location, or address, of another object. In an upcoming step, you will be tell this piece of data the object for which you want to store the address.
7. Add actions for each control and menu item.
The other symbol next to the outlet is a small gray circle with crosshairs and it is called a target. These are to what the buttons, sliders, menu items and so forth will be shooting their requests. Instead of being the address of an object like the outlet is, an action occurs when the target is hit. An action is a special type of method.
Highlight MyController again if it isn't still in focus. Go back to the Classes menu again and this time choose Add Action. Start typing your action name and it will replace the generic myAction: that appeared. Make sure that you end each name with a colon.
Here are the ones I used:
pushPanicButton:
checkDuplicates:
radioAM:
radioFM:
radioSW:
popCorn:
popCork:
popWeasel:
pullGravity:
pullMagnetism:
slideHeadFirst:
comboLunch:
menuEditWipeOut:
menuDinnerChicken:
menuDinnerTuna:
menuDinnerFlounder:
menuDinnerHalibut:
Those of you in the express lane need only create the pushPanicButton: and menuEditWipeOut: actions.
8. Instantiate the new controller.
What you've done in the previous three steps is create a class (or factory) for a controller much like an architect creates a blueprint for a house. Can you live in a blueprint? No, you have to build a house according to that blueprint to have something to inhabit. Similarly, you have to create an instance of the controller class in order to use it in your program. The verb, "Instantiate", was invented in 1949, according to my dictionary, to compress the phrase "create an instance" into a single word.
Now that the concept is clear in your mind, go to the Classes menu and choose Instantiate. Click on the Instances tab of the MainMenu.nib window and you'll see that there's good news and there's bad news (see Figure 9).
Figure 9. The MainMenu.nib Window with Instances Tab Selected.
The good news is now you see a cube labeled "MyController" in the window (provided you are in icon view. If you are in list view, look at the far right side of the window at the top of the scrolling area, and you will see a small square with squares in it. That is the icon-view button. The square below it with the horizontal lines will get you back to list view. Now you're marveling at the cube you've created and are wondering what could be bad about this. In informal discussions, we often use the terms "class" and "object" interchangeably, when, in fact, an object is an instance of a class. To return to the metaphor of people, a class is like a job description and an object is like the living, breathing person who has the job. The MyController you have built from steps 5–7 is a class and the one you just instantiated here is an object of that class. The convention in Objective-C is to capitalize the first letter of a class, and to have an object start with a lower-case letter. Double-click on the words "MyController" and rename it "itsMyController." Now, your joy can be unbridled!
Connect the Controller to the Views (Visible Things).
Now that the cube representing the controller appears in the MainMenu.nib window, you have a visual representation of all of the objects in your project. Perhaps you think it might be pretty cool if you could connect them all up with some points and clicks of the mouse. Well, you can! The basic principle is that you click on the "from" item, hold down the Control key, drag to the "to" item and let go.
9. Connect the controller to the text field.
For an outlet, you want data to flow from the controller to the outlet object. Click once on the icon called "itsMyController" to select it. Now, hold down the Control key and drag the L-shaped line to the text field. This is shown in Figure 10. A dialog box opens up an allows you to select an outlet. Choose theTextField and then click on Connect.
Figure 10. Making the Connection.
10. Connect the controls and menu items to the controller and select the right actions.
Fortunately, connecting views (visible things) to the controller works the same way. This time the request for action comes from the view (visible thing) and goes to the controller Select, say, a button, then Control-drag to the "itsMyController" icon. The difference here is that you are now prompted for an action. This means choosing the radio buttons individually (as NSButtonCells) to connect each one with the right target. Likewise with the pop-up and pull-down menus, except it is NSMenuItems you must connect individually.
In the dialog that pops up after you've made a graphical connection, the actions you may connect to are listed in the right-hand column. If not, click on target in the left-hand column.
Menu items behave exactly the same way, so all you have to do is Control-drag from the menu item to the controller in order to connect the menu item with the action it should do.
Generate the Code and Write the One Line.
11. Create the skeleton of the code for the controller.
When you've completed this work, a little treat appears. Since you've been doing repetitive connections for a while, you probably are not looking forward to writing code for all of those actions. The good news is: you don't have to. Simply click once on the "MyController" icon and go to Classes>Create files... and navigate to the folder of this project. Ba-da-boom, ba-da-bing! The basic interface file (ending in .h and called a header file in C) and its implementation file (ending in .m, the Objective-C source file ending analogous to .c in C and .cpp in C++) appear in magically ProjectBuilder.
You can now save your nib file and quit InterfaceBuilder now that your interface is, uh, built. Click once on the ProjectBuilder icon in the Dock to bring it out of hiding. The version of ProjectBuilder/InterfaceBuilder that I am currently using puts the MyController.m and MyController.h files in strange places. Please put them in the top folder, the Classes folder. Thank you.
The concept of separate files for interface and implementation makes a lot more sense as projects get bigger and bigger. It is a better idea, therefore, to get you into good habits when your starting off small than trying to force change on you after you've developed bad ones and are entangled in a huge mess. The interface is the place where you introduce the data (variables, members) and show what methods (functions, subroutines) are available to the object. The implementation is where you put the mojo, the detailed instructions of how to actually do the things you promise in the interface.
Here is the code generated for you and placed in MyController.h. After you examine it, I will explain some of the features of this code that are unique to it and not Objective-C concepts you can get by reading Chapter 3 of the book mentioned above.
Listing 1: The interface of the controller class.
#import <Cocoa/Cocoa.h>
@interface MyController : NSObject
{
IBOutlet id theTextField;
}
- (IBAction)checkDuplicates:(id)sender;
- (IBAction)comboLunch:(id)sender;
- (IBAction)menuDinnerChicken:(id)sender;
- (IBAction)menuDinnerFlounder:(id)sender;
- (IBAction)menuDinnerHalibut:(id)sender;
- (IBAction)menuDinnerTuna:(id)sender;
- (IBAction)menuEditWipeOut:(id)sender;
- (IBAction)popCorn:(id)sender;
- (IBAction)popToast:(id)sender;
- (IBAction)popWeasel:(id)sender;
- (IBAction)pullGravity:(id)sender;
- (IBAction)pullMagnetism:(id)sender;
- (IBAction)pushPanicButton:(id)sender;
- (IBAction)radioAM:(id)sender;
- (IBAction)radioFM:(id)sender;
- (IBAction)radioSW:(id)sender;
- (IBAction)slideHeadFirst:(id)sender;
@end
"IBOutlet" means nothing, it is just there to remind you of the purpose of the object there. You may be offended by this apparent waste of space, but remember, code is not just a communication between you and the machine, it is a record of your intended goals for others to read (and one of them can be you months or years later.)
"IBAction" means "void" which, in the case of a method, states that it returns no value.
"sender" refers to the view (visible thing) that is causing the action. As you progress, you may be interested in knowing the value to which the slider is pointing, for instance, and then you will make use of the sender object.
Here is a question you may ask: O.K., wise guy, you said that each user interface element was an object, but I only see one, "MyController", where are the others? Good question, although I could do without the attitude. The views (visible things) are stored in the nib file — the construction and functional details of "My Window" and everything in it is kept in the nib file. To keep you on the edge of your seat, notice that the controller is different from the views (visible things). Hmmmmm?
12. Add this code to any of the actions.
Go to the MyController.m file and place your cursor between the curly braces of the first method, checkDuplicates().
Now, the moment you have all been waiting for (or dreading): Here is the one line of code you need to make this project do something.
[theTextField setStringValue:@"You've done this action."];
How did I come up with that? When I put the text field in "My Window" is noticed that its Inspector indicated that it was an NSTextField. I went to the Application Kit Table of Contents page (AppKitTOC.html) which came with the Developer Tools, but is also at Apple's web site. I clicked on NSTextField and scanned the available methods and did not find a suitable one. I remembered that classes inherit the methods of their parents. At the top of the page, I saw that NSTextField is a child of NSControl (the lineage is expressed with the closest ancestor being the leftmost in the chain.) On the page for NSControl, I found the setStringValue: method which was exactly what I needed.
Listing 2. The top lines of an early version of the implementation of the controller class.
#import "MyController.h"
@implementation MyController
- (IBAction)checkDuplicates:(id)sender
{
[theTextField setStringValue:@"You've done this action."];
}
Here, the square brackets indicate that enclosed text is a "message" where one object tells another to do something.
The message has two major parts: the first is the receiver (in this case, theTextField). It is the object that receives the request from the bossy controller.
The second part is the method (setStringValue:) and it represents the method or function for the receiver to perform. The method must be one that the receiver can do or you'll get an error.
The colon ":" is significant because the number of colons in a method definition indicates how many parameters, or arguments, that the method requires. Here, the one colon means that one parameter is required for this method and it just so happens that it needs to be an NSString. A string is a group of letters, numbers and other characters. However, you want to make sure that the compiler (the program that translates the code you written as text that someone could read into instructions that a computer can read) does not think your string is part of a computer language or a name of a class, variable, method, etc. In C, one simply puts a string between double quotes. An NSString offers many advantages and is most easily created by putting an at-sign ("@") before the string you enclose in double quotes.
Don't forget the semi-colon after the message as that signifies that the "line" of code is complete. A "line" of code in any of the C-based languages can span several lines of screen (or paper) and often improves clarity. For that capability, we accept the responsibility of explicitly terminating every line of code with a semi-colon. If you are new to programming, you will probably make this error repeatedly, but fortunately, most compilers these days are smart enough to show you where you may have forgotten to put a semi-colon.
Feature: The Model-View-Controller Scheme.
There is a method of creating large projects by creating three different types of objects. This being a small project you've only worked with two out of three (and Meat Loaf fans would say that ain't bad.) You have used the views (visible things) provided by InterfaceBuilder and dealt with them using the controller you created. In the controller, you wrote the single line of code to take the input and generate an output, but you can imagine that you may want to send the input to an object that could some fancy stuff with it and gives you back some amazing result that the controller could pass back into the views. These objects that work the really interesting stuff on the data are called models. Creating a project in this manner observes the model-view-controller scheme.
There are many benefits to doing your work this way. The models and views, particularly custom views you may develop later on, are reusable in various projects. It makes a large application easier to maintain by allowing tweaking of models or views without having to worry about the other - the controller or controllers provide the separation to ensure this. This means, of course, that the controllers are very specialized for each project and are generally not reusable.
Some projects may get a performance boost if you combine the functionality of controllers with either models or views, but that probably won't be a burning issue for most of us. The model-view-controller method is an excellent way to structure a project, but I wish it were called model-controller-view to emphasize the separation of the model and view by the controller.
13. Copy and paste this line to all of the other actions.
Highlight the message you just wrote and choose Edit>Copy (Cmd-C). Paste (Cmd-V) this line between all of the action methods in the implementation file, MyController.m. Pasting copies of this function does not really count as writing, so the title is still truthful, right?
14. Allow user to modify the string to be more useful.
I also didn't say you wouldn't have to modify that single line. As we discussed above, a string is a group of characters that were not part of a programming language. If you are modifying text that is not as restricted as actual code, this activity shouldn't count as writing code. You don't really have to do this, but your application will be awfully boring if every time you do something, the generic message always shows up.
Listing 3: The final version of the implementation of the controller class.
#import "MyController.h"
@implementation MyController
- (IBAction)checkDuplicates:(id)sender
{
[theTextField setStringValue:@"You chose duplicate checks."];
}
- (IBAction)comboLunch:(id)sender
{
[theTextField setStringValue:@"You have chosen your lunch combo."];
}
- (IBAction)menuDinnerChicken:(id)sender
{
[theTextField setStringValue:@"You selected chicken for dinner."];
}
- (IBAction)menuDinnerFlounder:(id)sender
{
[theTextField setStringValue:@"You selected flounder for dinner."];
}
- (IBAction)menuDinnerHalibut:(id)sender
{
[theTextField setStringValue:@"You selected halibut for dinner."];
}
- (IBAction)menuDinnerTuna:(id)sender
{
[theTextField setStringValue:@"You selected tuna for dinner."];
}
- (IBAction)menuEditWipeOut:(id)sender
{
[theTextField setStringValue:@"You want to wipe everything out?"];
}
- (IBAction)popCorn:(id)sender
{
[theTextField setStringValue:@"You have popped corn."];
}
- (IBAction)popToast:(id)sender
{
[theTextField setStringValue:@"You have popped toast."];
}
- (IBAction)popWeasel:(id)sender
{
[theTextField setStringValue:@"Pop goes the weasel."];
}
- (IBAction)pullGravity:(id)sender
{
[theTextField setStringValue:@"Gravity pulls all."];
}
- (IBAction)pullMagnetism:(id)sender
{
[theTextField setStringValue:@"Magnetism pulls iron."];
}
- (IBAction)pushPanicButton:(id)sender
{
[theTextField setStringValue:@"Calm down, all will be fine."];
}
- (IBAction)radioAM:(id)sender
{
[theTextField setStringValue:@"AM radio - traffic, weather and news"];
}
- (IBAction)radioFM:(id)sender
{
[theTextField setStringValue:@"FM radio - all hits, all day, all night."];
}
- (IBAction)radioSW:(id)sender
{
[theTextField setStringValue:@"Short Wave - Ham it up!"];
}
- (IBAction)slideHeadFirst:(id)sender
{
[theTextField setStringValue:@"Safe at home - we win!"];
}
@end
Bring the Project to Life
15. Build and run it.
Simply go to the Build Menu and select "Build and Run." If errors occur, double-check the code you wrote in MyController.m to ensure that the curly braces, the square brackets and the quotes all have matches. Make sure that each string in quotes has an at-sign in front of it and that there is a semi-colon after each closing square bracket.
If everything goes well, on the other hand, you may be disappointed that nothing has apparently happened except that the menu bar reflects your changes. Just go to the Window menu and select "Bring All to Front". The reason you needed to do this manually is because I did not discuss the lines of code you would need to bring the window to the front on startup. You should now see you creation in all of its glory!
Click the buttons, slide the slider, choose each item in the pop-up and pull-down menus, click on your menu entries and try the keyboard shortcuts. Did they all work as planned? If so, congratulations, otherwise you may notice things you forgot to connect or connected in correctly.
When you are finished, you can click Cmd-Q or go to MyFirstProject>Quit to quit your application.
Now, was that fun or what?!
Conclusion
If you are reading this, you have covered a lot of ground in a short time and you should be proud of yourself. You've learned how to use ProjectBuilder and InterfaceBuilder and were introduced to objects and classes, Objective-C, inheritance, messages, views (visible things), menu making, target/action, outlets, connections between objects, model-view-controller, human interface guidelines, AppKit and Foundation (which make up the Cocoa framework), methods, receivers, interface and implementation, inspectors, keyboard shortcuts, instantiating and subclassing (I hope I haven't missed anyone.) By touching on these topics, I hope you got a good "big picture" view of what Cocoa involves and are encouraged to pursue learning of this amazing way to making our Macs even more useful, friendly and fun. Best of luck and thanks for your time.
David Trevas lives in Houston, Texas with his wife and daughter, two dogs and two Macs.