Welcome back to Part 2 of Cocoa 101: Object-Oriented Programming for the Masses! I received a lot of great feedback on my previous article, and I’m looking forward to sharing with you once again what I’ve learned about Cocoa and the Objective-C language. If you missed Part 1 of this tutorial, read it here.
To start off Part 2, I’d like to take just a brief moment to explain why I picked this title (Object-Oriented Programming for the Masses) for my article. I believe that Cocoa is the easiest and most logical method of GUI-based, object-oriented application programming available in a mainstream operating system. While many programming experts have welcomed Cocoa with open arms because of its RAD (Rapid Application Development) qualities and powerful foundation classes, I see its major strength as being a window of opportunity for regular “Joe” users with some technical computer skills to “make the leap” and become software producers, not just software consumers. And no, I’m not just talking through my hat. The amount of innovation I’m seeing right now in the Mac OS X software community is staggering, and much of it is coming from people who have slowly grown into the role of being a software developer, not people with 20+ years experience in programming and boasting several degrees in computer science. Though the fruits of my own labor have yet to be shown to the public, slowly but surely I find myself growing into the role of software developer as well. And I can easily claim that Cocoa is the reason, the only reason, that this has occurred.
Now if you’ll recall, last time I introduced you to a few of the basics of Objective-C. In particular, the fact that every Objective-C object belongs to a class. Also, I stated that the concept of encapsulation is important in object-oriented programming — that is, the implementation of an object is hidden behind its interface. That’s where I left off previously, and that’s where we’ll pick up the trail this time.
In spite of all that was presented in Part 1, I missed showing you one very important thing: exactly how to define a class in code. This is because it’s best to know a bit more about Cocoa before you can understand how that process works. So I’ll use this opportunity to introduce a few of the basics of the Cocoa framework, as well continue on with our exploration of Objective-C.
Remember, every Objective-C class features at least one of these attributes: class methods (for the class objects), instance methods (for the regular object instances), and instance variables. So how exactly is a class definition created? Objective-C typically follows the grand C tradition of splitting up groups of code (in this case, objects) into two files: a header file and the actual code file. In Objective-C, this usually translates as: the interface file and the implementation file. For example, a MyPerson
class would be defined using two files: MyPerson.h
and MyPerson.m
. The .h is the standard C header extension, and the .m stands for “Objective-C code module”.
Let’s create this MyPerson
class right now, which we’ll use as an example object for the duration of this article. I’ll pretend that objects can do anything in the world, just to make things fun. Say you want to store a few details about a person in a MyPerson
object. This object should store information for the person’s full name, address, date of birth, and hair color. You also want to be able to send this person a postcard with your name and return address on it along with a message. (I told you objects can do anything!) The interface file (MyPerson.h
) might end up looking something like this:
#import <Cocoa/Cocoa.h>@interface MyPerson : NSObject {
NSString *fullName;
NSString *address;
NSCalendarDate *dateOfBirth;
NSColor *hairColor;
}// Accessor methods
– (void)setFullname:(NSString *)newName;
– (NSString *)fullname;
– (void)setAddress:(NSString *)newAddress;
– (NSString *)address;
– (void)setDateOfBirth:(NSCalendarDate *)newDate;
– (NSCalendarDate *)dateOfBirth;
– (void)setHairColor:(NSColor *)newColor;
– (NSColor *)hairColor;// Other methods
– (void)sendPostcardWithMessage:(NSString *)message toAddress:(NSString *)address
fromName:(NSString *)name returnAddress:(NSString *)returnAddress;@end
Makes sense? No? Well, we’ll soon get to the bottom of it. The first line is an import “complier directive”. A compiler directive tells the software compiler what to do before processing your code. In this case, it’s saying to import the main header file for the Cocoa framework. Cocoa is actually made up of two “kits”, the Foundation Kit and the Application Kit, but Cocoa.h
imports them both. I’ll explain some of the differences between the two kits in a little while.
The next line is where the Objective-C interface starts for your object. The interface declaration is indicated by the @interface
bit of code and ends where @end
is located (i. e., at the bottom of this file). After @interface
we have the name of the class (MyPerson
). Then there’s a colon followed by the name of the class that MyPerson
inherits from. Since MyPerson
doesn’t require any specific functionality offered by any particular Cocoa class, we’re just inheriting from the root object, i. e., NSObject
.
Now we’ve arrived at the spot where your object’s instance variables are declared. Right after NSObject
is an open curly brace. From here on until the close curly brace, all of the object’s instance variables are declared. Now instead of using standard C types such as char
(for strings), int
, etc., we’re opting to use data objects from Cocoa’s Foundation Kit. There are many reasons to use Cocoa data objects rather than simple C types, not the least of which is that these objects come built-in with a ton of functionality that will prove to be very useful in any project you build.
So here I’m declaring the instance variables fullName
and NSString
(which is, of course, Cocoa’s default string class for storing text). Now why don’t I just declare these variables as being of type id
? After all, since Objective-C supports dynamic typing, all objects can always be declared using the id
type. Well, while that’s true, it’s a good idea to “statically type” variables whenever possible because (a) the compiler will warn you if you’re trying to send messages to an object that probably aren’t supported by that object, and (b) it shows visually (to the programmer) what kind of class the object belongs to.
With that out of the way, we’ve come to the last two instance variables: dateOfBirth
and hairColor
. dateOfBirth
belongs to the NSCalendarDate
class. NSCalendarDate is an object that represents a point in time in the context of the standard western Gregorian calendar. NSCalendarDate
is actually a subclass of NSDate
, which represents a more low-level interface to time. I’ve chosen to use NSCalendarDate
because that class provides lots of groovy methods that return useful bits of data, such as dayOfMonth
or minuteOfHour
and the like. The last variable, hairColor
, belongs to the class NSColor
. NSColor
actually is part of Cocoa’s Application Kit, because colors aren’t usually used outside of the context of a visible application (as opposed to a background process or something like that). NSColor
is an object used to represent a color defined in a color space (usually the standard RGB color space of computer screens). The nice thing about NSColor
is that it provides a lot of handy class methods such as brownColor
, redColor
, greenColor
, etc., that allocate and initiallize an NSColor
object and hand it back to you with the proper color values already set. Cool, huh? Of course, most people don’t have green hair, but they might have a green car or even a green house!
Now we’re on to the accessor methods. I mentioned in Part 1 that accessor methods are the preferred way to allow other objects to access or modify your object’s instance variables. Here, we have a pair of accessor methods for each variable. So for the fullName
variable, we declare two methods: setFullName:
and fullName
. setFullName:
is interesting, because it’s the first time I’ve presented an Objective-C method with an argument. Objective-C differs from some other object-oriented languages in that it uses named arguments. In other words, each variable that you pass on to a method has a name before it. All of these names comprise the full name of a method, also known as the method’s signature. This results in the fact that you can have more than one method that starts the same way. For instance, in addition to the setFullName:
method declared, we could declare a setFullName:maidenName:
method. It might look like this:
– (void)setFullName:(NSString *)newName maidenName:(NSString*)newMaidenName;
Note that the names of the actual variables contained in the method declaration aren’t part of the method’s signature. In fact, those names could be anything. The line above would mean absolutely the same as this:
– (void)setFullName:(NSString *)abc maidenName:(NSString *)xyz;
OK, so now you know a bit more about methods and their arguments. Most of the time, however, simple accessor method pairs simply feature a “set” method with one argument (the new value, or object, to be assigned to the instance variable), and a “retrieval” method that’s simply the name of the instance variable and uses that variable as it’s return value. Now this convention of having two accessor methods like that (“setBlahBlahBlah” and “blahBlahBlah”) isn’t simply around just for kicks and grins. It actually comes in very handy in several cases because some of the more complicated Cocoa design patterns automatically assume that your objects feature accessor methods declared in that manner. So it’s usually a very good idea to stick to the convention, unless there’s some amazingly overriding reason to do so.
Believe it or not, we’re almost done with the interface file! After all of the accessor methods, we have only one “non-standard” method declared: sendPostcardWithMessage:toAddress:fromName:returnAddress:
. Whew! That’s a pretty long method signature, with four arguments no less! This method allows us to tell a MyPerson
object to send a postcard with a certain message to a certain address and specify the name of the person who sent it and also that person’s return address. Because of the named arguments, the usage of this method is self-explanatory. It wouldn’t be as clear in some other computer languages. So let’s say that in another object, you’ve created a MyPerson
object and assigned it to the variable janeDoe
. You might send it a message like this:
[janeDoe sendPostcardWithMessage:@"Hi! Wish you were here! Bye!" toAddress:@"1234 Cherry Lane, Bigtown, CA 98765" fromName:@"Joe Smith" returnAddress:@"192 Hotel Drive, Paradiseville, HI 91827"];
Wordy, but very understandable. If you’re wondering what all those “@” signs are before the quoted text, that’s a special compiler directive that says “create an NSString
object containing the following text”. It’s the easiest way to create Cocoa strings, and you’ll find yourself using it almost everywhere all the time.
With the MyPerson
interface out of the way, we arrive at the implementation file: MyPerson.m
. Let’s take it bit by bit this time. The first bit might look like this:
#import “MyPerson.h”@implementation MyPerson
– (id)init
{
self = [super init];
if (self) {
fullName = @””;
address = @””;
dateOfBirth = [[NSCalendarDate calendarDate] retain];
hairColor = [[NSColor clearColor] retain];
}
return self;
}
The first line is an import directive that says to import the counterpart header file where the object’s interface is declared. If the interface weren’t imported, then the object implementation wouldn’t know what the heck it’s implementing!
Next we have a simple init
method. As presented in Part 1, the first order of business to send a message to the superclass (NSObject
) to initialize the object, and the returned object pointer is assigned to self
. Now the next step (if (self) {
) is theoretically optional. It’s very unlikely that the NSObject
initialization process will fail, but, just in case, we’ll start assigning values (we’ll call them values, but they’re really only pointers to objects containing values) to the instance variables only if self
equals anything other than nil
(nil
is an Objective-C data type representing a null pointer, a “non-object” if you will).
We then assign blank NSString
values (really, pointers to the newly-created string objects) to fullName
and address
. dateOfBirth
is assigned an NSCalendarDate
value representing the very point in time when that statement is executed. In other words, “now”. The hairColor
variable is assigned an NSColor
value representing a no color value (a clear color). Note that both of these messages are each nested in a retain message. You’ll learn all about that in a moment. Hmm, when you sum it up, basically this person has no name, no address, was just born, and has transparent hair. Pretty freaky, isn’t it?
But wait! That’s what the accessor methods are for: to assign “real” values to these variables! Here’s the code for them:
– (void)setFullname:(NSString *)newName
{
[newName retain];
[fullName release];
fullName = newName;
}
– (NSString *)fullname { return fullName; }– (void)setAddress:(NSString *)newAddress
{
[newAddress retain];
[address release];
address = newAddress;
}
– (NSString *)address { return address; }– (void)setDateOfBirth:(NSCalendarDate *)newDate
{
[newDate retain];
[dateOfBirth release];
dateOfBirth = newDate;
}
– (NSCalendarDate *)dateOfBirth { return dateOfBirth; }– (void)setHairColor:(NSColor *)newColor
{
[newColor retain];
[hairColor release];
hairColor = newColor;
}
– (NSColor *)hairColor { return hairColor; }
Looks scary, doesn’t it! What’s with all that retain and release jargon? Only one of the most important concepts to understand about the Cocoa framework: memory management. The bane of the programming world, memory management is one of those things that most people just wish they could ignore and forget about. And, in some languages, fancy run-time engine techniques such as “garbage collection” really do allow people to forget about it most of the time. While Cocoa doesn’t use garbage collection, it uses another kind of memory management that is by all accounts pretty simple as well, and it’s typically called “retain and release”. This is how it works:
Object A (we won’t discuss how Object A was created) allocates and initializes Object B. Object B automatically starts out with a retain count of 1. In other words, Object B is retained by Object A. Now let’s say that Object A no longer needs to use Object B, maybe because Object A was “deallocated” (in other words, it no longer exists in memory). What happens to Object B? I’m afraid it just sits around in memory forever (or until your application quits) and is completely useless because there are no more pointers to it anywhere in your application. This is called a memory leak, and memory leaks are bad because lots of big memory leaks will drastically slow down the host computer and make your users angry. And angry users are to be avoided at all costs, believe me.
What needs to happen is that Object B is released when Object A no longer needs to use it. This is what the [objectB release];
code is for. Releasing an object doesn’t automatically deallocate it however. An object is deallocated only when its retain count goes down to 0. When an object has a retain count of 1, and it’s sent a release message, its retain count will change to 0 and it will be deallocated. But what if there’s another object, Object C, that is passed a pointer to Object B from Object A? What if Object A releases Object B, and then Object C tries to use Object B? What will happen? Your application will crash. Crash and burn, baby. That will make your users even more angry, and you wouldn’t want that! So, basically, Object C should send a retain message to Object B so that it will still be in memory when Object A releases it. In other words, Object B’s retain count will go up to 2, so that when it’s released by Object A, its retain count will go down to just 1 and it will still be in memory and available for use.
So, you see, it’s really quite simple. Every object initialization or retain message should be balanced by a release message. In other words, 1 + 1 + 1 – 1 – 1 – 1 = 0. There’s a catch here, however. Sometimes you’re going to lose a pointer to an object before you have had a chance to release it (maybe because you bypassed assigning the pointer to a variable). Sometimes you’re going to create an object and then immediately pass the pointer along to another object that isn’t guaranteed to release the object. In these cases, there is no clear solution based on a simple release/retain mechanism. That’s why Cocoa provides an ingenious solution: an autorelease pool. The idea is that a “third-party object” (an autorelease pool) will retain an object for a short period of time (normally one loop of an application’s “event cycle”) and then release it. These kinds of objects are usually considered “temporary” objects, that is, they are used in situations where objects need to be used only for a short period of time. The way you autorelease an object (i. e., add it to the current autorelease pool) is simply by sending it an autorelease message rather than a release message. Let’s break this down again:
Object A creates Object B (which has a retain count of 1), then autoreleases it and hands it over to Object C, which uses it in just one method. Shortly after that method has been executed, the autorelease pool sends Object B a release message which brings the retain count down to 0 and Object B is deallocated.
The really nice thing about the autorelease pool is that if an object’s retain count is above 1, then it won’t be deallocated when the autorelease pool sends it a release message. So you can autorelease an object with a retain count above 1, knowing that it won’t be deallocated prematurely. And you can send an object a retain message after it’s been autoreleased, so that it will be usable after it’s been released by the autorelease pool. That’s actually something to be very careful about when using autorelease pools: you don’t want an object to be released by the autorelease pool before you’re done using it, because then your application will crash. So always retain an object if you want to make sure it won’t be autoreleased before you’re done using it.
By the way, you might be interested to know that autorelease pools are actually Cocoa objects belonging to the class NSAutoreleasePool
, and you can create more than one autorelease pool during the duration of your application. However, regular GUI-based Cocoa applications have a default autorelease pool created automatically, so you don’t have to worry about creating one yourself.
Going back to MyPerson
‘s accessor methods, you can see that each of the “set” methods sends a retain message to the new object, sends a release method to the old object, and then makes the instance variable point to the new object. Notice the retain, then release order here. This is the best order, because if the object being pointed to by the method argument is the exact same object that the instance variable points to, it’s retain count will just go up 1 and then down 1, which is like nothing happened. Think what would happen if the object were released, then retained. If it were released with a retain count of one, it would be deallocated, and the retain message would then be sent to a invalid piece of memory, causing your application to crash. So retain, then release, is the only order that can be used if you use this style of coding (there are, in fact, several other methodologies different people use to get around this problem, but I personally like the one outlined above the best).
One more thing that I’d like to mention is, if you look back at the init
method for MyPerson
, you’ll see that the new date and color objects are both being sent a retain message. Why? Well, the convention in Cocoa is that any “convenience” class methods that automatically allocate and initialize an object for you also autorelease the object before returning it. So, if you want to make sure the object isn’t deallocated when it’s released by the autorelease pool, you have to send it a retain message, which is what we’re doing in our init
method.
Now the accessor methods which are for retrieving a value are considerably easier. They fit on just one line, in fact, because all the code does is return the value. Easy, no?
Here we come to the final bit of code for the MyPerson
implementation:
– (void)sendPostcardWithMessage:(NSString *)message toAddress:(NSString *)address
fromName:(NSString *)name returnAddress:(NSString *)returnAddress
{
// send postcard code goes here
}– (void)dealloc
{
[fullName release];
[address release];
[dateOfBirth release];
[hairColor release];
[super dealloc];
}@end
See that @end
at the end there? That tells the compiler that your implementation code has ended. Good thing too, because we don’t want this article to get too long! All kidding aside, there really isn’t too much going on here. Obviously, I haven’t implemented the send postcard code because, well, that would be quite a feat, wouldn’t it? Moving right along to the dealloc
method: this method is called automatically by the NSObject
class itself when the object’s retain count has gone down to 0, allowing you to take care of any “cleanup” needed before the object is deallocated. Since we want to be good citizens, we’ll release all of our instance variables before the object is deallocated. We also don’t want to forget to allow the superclass to get its cleanup work done too, so we’ll send it a dealloc message at the end.
So there you have it. A more-or-less fully complete Objective-C class that employs several other Cocoa classes. Where do we go from here? I think this would be a good time to give a brief overview of what actually is in the Cocoa framework and what tools Apple makes available to use in creating Cocoa applications. Then I’ll wrap up Part 2 by giving you a few more Internet resources to check out as well as some books that I’ve found to be very valuable.
As I’ve said before, the Cocoa framework is made up of two “sub-frameworks”, or kits known as the Foundation Kit and the Application Kit (Apple now calls the Foundation Kit just “Foundation”, but I prefer to call it the Foundation Kit). Why the two kits, rather than twenty, or one? Generally, the Foundation Kit contains all the basic data classes, classes that enhance the Objective-C language, and classes that allow access to low-level system services. The Application Kit contains all high-level application services classes, all the view (GUI) classes, multimedia services classes, and additional data classes (like color classes).
So how many classes are in these kits? Lots, and when you put them to work, they will save you a huge amount of precious time which would be better spent building the real guts of your application. The Foundation Kit contains classes for many different types of values (numbers for instance), strings (there are a number of classes that provide nifty ways of storing and manipulating text), binary data, dates, and even time zones. Another group of classes that are very useful are the container classes, such as arrays (similar to regular C arrays, these objects “contain” multiple objects ordered by number), dictionaries (objects that allow access to contained objects via associated key objects), and sets (which contain multiple, unique objects in an unordered fashion). Other classes include a file manager, a notification center (notifications are used all over the Cocoa framework; they allow you to easily broadcast different types of messages to any objects that have registered themselves with the notification center to receive those types of messages), a timer (an object that will send a message repeatedly at certain intervals to any object you specify), and many more.
The beautiful thing about the Cocoa data classes is the easy yet extremely powerful way in which they can save and open files. For example, you can create a string object, put some text in it, send it one single message, and poof! A text file is saved on your hard drive. Loading a text file back into a string object is similarly a no-brainer. But it gets even better. You can add a bunch of standard data objects to an array object, sent it a save message, and it will actually generate an XML-based “property list” file containing an entire tree structure of your data objects. You can nest the objects too: put some string objects in an array object, put that array object along with some other objects in a dictionary object, put that dictionary object along with another array object in another dictionary object, and then save that dictionary object. It will all be saved as a human-readable XML file that can be parsed using any XML parser on the planet. This method of data storage is so easy to use, so open, and so seamless that most Cocoa developers use it all the time, even Apple. In fact, Safari uses a property list file to store all of its bookmarks, and iTunes and iPhoto export a copy of their data libraries as property lists so that all the new iLife applications can access each other’s data. The default format for storing application preferences is an XML property list as well.
Now what about the Application Kit? What kind of groovy things can we find there? How about windows, menus, buttons, sliders, tables, outline views, combo boxes, text boxes, rich text editors, toolbars, multiple-column data browsers, image views, and a whole lot more! The Application Kit is chock full of classes that are subclasses of the abstract class known as NSView
. An abstract class is a class which, on its own, is fairly useless; it only does something interesting when it’s subclassed. NSView
provides a clean and simple interface to the display of graphics. It doesn’t feature any drawing capabilities itself; it simply provides a “canvas” on which you can draw using other Cocoa classes. NSView
is actually a subclass of NSResponder
, which provides event handling such as for mouse and keyboard events. There’s also a number of classes which stem off of the NSCell
class. Many view objects use lightweight cell objects to perform the actual drawing for display and handling of events. Some view objects, like tables, use multiple cells at once. The Application Kit also contains numerous other classes which help with tasks such as printing, managing the clipboard, using standard interface elements such as Open and Save File panels, and the like.
That gives you a very rough idea of what kind of things you’ll find in the Cocoa framework. But, in the end, the main question is this: how do you actually create a Cocoa application? Apple provides two main tools: Project Builder and Interface Builder. Project Builder is an IDE (Integrated Development Environment) that you use to create and edit application projects. Cocoa is but one of the many programming frameworks supported by Project Builder, and you can use Project Builder to build applications written in standard C, Java, and other languages as well. Project Builder handles all of the mundane tasks of creating a basic Cocoa application, setting up a build process for compiling the application, loading up debugging tools, etc. for you. In fact, you can literally go into Project Builder, select New Project from the File menu, choose a folder to save it in, and then press the Build & Run button in the toolbar to run your new Cocoa application. A blank window will appear along with a menu bar that really works — all with you having written no code at all! Where does this window and menu bar come from? Read on…
Interface Builder, the other main tool I mentioned above, is one of the more brilliant aspects of the Cocoa development environment. Interface Builder allows you to access many of the Application Kit classes graphically. More to the point, it allows you to create the graphical interfaces for your applications and “hook up” your base application objects with your interface objects. Basically, what happens is that Interface Builder creates all these objects and “saves” them into a single package called a nib file (“nib” used to stand for NeXT Interface Builder, but now it just stands for nib). Just about every Cocoa application on the planet uses at least one nib file for storing all of the interface and related base objects. Nib files are loaded dynamically when your application is run, which means that all of the objects in the nib files are loaded into memory and are available for use. In some cases, all of the custom objects you use in your application can be loaded from a nib. Applications can also dynamically load nib files stored in “bundles” while the app is running, which lets you create an entire plug-in architecture for your application with a minimum of hassle.
So to answer the question of where does the window and menu bar of a brand new Cooca application come from: it is loaded from the default nib file that Project Builder automatically generates. Project Builder and Interface Builder are somewhat integrated; they can talk to each other and cooperate on how your project’s code and its interface are glued together. I won’t go into all of the details here, but, suffice it to say, you’ll be toggling back and forth between Project Builder and Interface Builder a lot while developing Cocoa applications.
And now, at long last, we arrive at the end of Part 2 of Cocoa 101: Object-Oriented Programming for the Masses. I’m very pleased to see that you’ve made it this far and that you’ve found Cocoa to be an interesting and hopefully exciting technology. I also hope that you have indeed learned a bit about what Cocoa is, what it can do, and the basics of how Objective-C works. I’m happy to report that all of the concepts presented in parts 1 and 2 of this article series constitute the basis of what it means to be a Cocoa developer, and you will find that just about everything you learn about Cocoa in the future will simply be building upon these core concepts.
I haven’t quite decided yet if I should write a Part 3 for Cocoa 101, because, in a sense, Apple and many others have already written Part 3. Apple provides some excellent Cocoa development tutorials and more detailed overviews of the Foundation Kit and Application Kit on the Cocoa Documentation Web Site, and there are numerous other Web sites and books which feature documentation, tutorials, and sample code for you to play with and tweak. In addition to the links I presented in the previous article, here are some more resources you should definitely check out (if I’ve overlooked anything, please forgive me!):
Web Sites & Mailing Lists
Stepwise
I was much remiss to leave Stepwise out of my earlier list of sites. Stepwise has been providing a valuable online resource for NeXTSTEP/Cocoa/WebObjects developers for over nine years (!) now and contains many great articles targeted at both beginners and advanced developers alike. Incidentally, Stepwise is run by Scott Anguish, co-author of one of the best Cocoa programming books currently available (in my humble opinion). See below for further details.
Omni Source Code
This is not for the faint of heart, but the Omni Group, a long-time NeXTSTEP/Cocoa developer, has made available a huge amount of source code in the form of several large and robust frameworks. The Omni frameworks have been used by many other third-party Cocoa developers, and it’s certainly worth taking a look at them and discovering all the many things they can be used for.
Cocoa Mailing List Archive
This site contains up-to-the-minute archives of both Apple’s Cocoa-Dev mailing list and the Omni Group’s popular MacOSX-dev mailing list. If you’re like me and you find receiving hundreds of geeky e-mails a day to be simply too daunting, then this site is for you. The search engine is an awesome feature as well.
Books
I’ve only purchased three Cocoa reference books so far, but there are several more than that on the marketplace now, so I’ll list all the ones I know about (or rather that Amazon.com knows about) here. I’ll put the ones that I actually have read at the top of the list along with a brief description.
Cocoa Programming for Mac OS X
by Aaron Hillegass of Big Nerd Ranch
This was the very first Cocoa book that I ever bought, and it helped me gain a solid understanding of what makes Cocoa tick, as well as presented many valuable good programming practices. Aaron makes fine use of real-world example projects to help you feel like you’re really accomplishing something, and his writing style is fun, yet philosophical. I would only knock it down to 4 stars out of 5 because I felt that a few of the more esoteric aspects of the Cocoa framework were somewhat overlooked. Then again, the book would have to be twice as big to cover everything, I suppose!
Cocoa Programming
by Scott Anguish, Erik M. Buck, and Donald A. Yacktman
This is the “mother of all Cocoa books”. Featuring over 1272 pages (!) of highly detailed information about nearly everything you could ever possibly want to know about Objective-C and Cocoa, this book is a must-have for anyone serious about Cocoa programming. The introductory sections on object-oriented programming concepts and design patterns and how they relate to the Cocoa framework are worth their weight in gold alone. While fairly technical in nature, I would say that any very enthusiastic beginner would appreciate what this book has to offer. I rate it 5 out of 5 stars!
Objective-C Pocket Reference
by Andrew Duncan
I bought this little guidebook because I knew that if I ever needed to remind myself of some Objective-C syntax and its usage, then this book would come in very handy. For what it is, it’s a great little resource.
Books I Wished I Had:
Cocoa Recipes for Mac OS X
by Bill Cheeseman
Learning Cocoa with Objective-C
by James Duncan Davidson
Building Cocoa Applications: A Step by Step Guide
by Simson Garfinkel and Michael K. Mahoney
Cocoa Programming for Dummies
by Erick Tejkowski
Cocoa in a Nutshell (coming soon)
by Michael Beam and James Duncan Davidson
About the Author:
Jared White is President and Art Director of Web site and graphics design company GaelDesign. He is also Editor-in-Chief of The Idea Basket, an e-zine featuring provocative news commentary, articles, editorials, and reviews related to software and interface design, the Internet, multimedia, and technology. Jared became a PC-to-Mac switcher in 2001 and has been having a blast with Cocoa ever since. He can be reached via e-mail at [email protected].
You don’t really touch much on the Cocoa part of things. Cocoa is a framework. Objective-C is a language.
What I would have found more interesting is an exploration of the Foundation and Appkit frameworks.
If, in your method – (void)dealloc { … }
you fail to call [super dealloc], as in the example I can see in this article, then your instance variables will be released (and garbage collected), but not those in any superclasses, and ultimately, the object itself will not deallocate. This causes a serious memory leak.
…very good.
Just this.
Ralf.
While I agree with dysprosia to an extent, perhaps the author is planning on continuing to write more articles, and Cocoa does require at least basic knowledge of Objective-C.
Very nice, and I would love to read more. Are you sure you don’t want to spend some time on Part 3, Jared? Pretty pleeeaaase? 😀
There is another (treacherous) memory error in the sample code…From the Cocoa documentation (Programming Topics – Memory Management):
It is possible for you to obtain a new object by invoking a class method of the form +className…. These class convenience methods create a new instance of the class, initialize it, and return it for you to use. Although you might think you are responsible for releasing objects created in this manner, that is not the case. Because the class method allocates the memory for the object, it is responsible for releasing that memory, thus class convenience methods should return their values autoreleased.
Thus, when you create in -init a NSCalendarDate or a NSColor through their class methods ([NCalendarDate calendarDate] & [NSColor clearColor]) you’re actually getting an object that will be autoreleased in a real world application. If it doesn’t fail on your tests it’s because you probably don’t have a running NSAutoreleasePool in place. For a correct programming, you should either:
– retain it (sensible thing to do, if you want to use it later)
– avoid a release in -dealloc (because the object will be gone anyway)
Memory management in Cocoa is wonderful when you finally manage it, but has its conventions…
Marko Riedel just started to write a GNUstep cookbook (in the same spirit as Perl cookbook), but it’s useable as well as a Cocoa cookbook 🙂
see http://www.roard.com/docs/cookbook/
other tutorials : http://www.roard.com/docs/
Happy stepping
As described, it sounds like Objective-C uses reference counting and language keywords for memory management.
I’ll stick with Java… (At the expense of running a background thread to handle GC)
Reference counting was a technique explored in C++ texts as a prototypical garbage collection approach. (Scott Myers, smart pointers? I could be wrong.)
It sounds like extra work for the programmer, implementing code to do reference checks everywhere. And if you miss some, potentially problems abound.
I’m not saying Java doesn’t have memory issues, just that the technique in objective-C has been discredited.
Ultimately a question of pre-compile checking through development tools (obj-c) or by the runtime system (java)
See
http://www.javaworld.com/javaworld/jw-08-1996/jw-08-gc_p.html
For details of GC. (A very old article, not accounting for advancements in JVM technology over nearly 7 years!!)
on reading my previous posting. I came off sounding as a smarmy Java person.
Nothing against Cocoa the environment, in fact Java bindings for *step such as
http://www.gnustep.it/jigs/index.html
look most interesting…
I’d hardly say that reference counting GC has become “discredited.” I haven’t used ObjC, but I have used the reference counting equivilent in C++. A reference counting smart pointer, like shared_ptr from Boost, is just as good as garbage collection in most cases. All you have to remember is that instead of:
int* i = new int
you do:
shared_ptr<int> i = new int
After this, ‘i’ will automatically take care of deallocating memory when it goes out of scope.
But when do we get into the chocolate theory behind cocoa?:)
And what about milk to mix ratio?:)
More seriously, it is nice to see someone writing about the great programming enviroment that Cocoa/OPENSTEP/GNUStep provide. Hopefully it will get a lot of Linux people interested in it since it would give Linux an edge over Windows in ease of programming and quality of programs, not to mention the fact that it would solve a lot of the compatibility across distros problems that can be seen today. Just think, no more package management problems and programs that have more consistant and user friendly interfaces than anything that Windows has to offer.
Well reference counting isn’t very difficult to program with, simpler of course than malloc/free, and it’s more efficient than garbage collecting … it’s a good solution.
Anyway you could use garbage collecting with GNUstep if you want, althrough I never used it (reference counting don’t bother me and I like to have a better control on what is done). But GC isn’t available with Cocoa.
(I’m being the devil’s advocate here – so forgive me…) I have a hard time imagining developers embracing Cocoa, let alone Objective-C. Why would anyone want to program in a language that effectively is only popular on one platform? Why would anyone want to use a closed framework that’s bound to a single platform? As an enterprise developer I can tell you that there’s no way any IT shop I know of would consider going back from Java or .NET. Yes, you can write Cocoa apps in Java. But again, why would I do this instead of SWT or Swing?? These facts alone will keep Apple in the consumer market – barely.
> Well reference counting … [is] more efficient than
> garbage collecting … it’s a good solution.
This is not always true, sometimes a pure GC is more efficient.
“(I’m being the devil’s advocate here – so forgive me…) I have a hard time imagining developers embracing Cocoa, let alone Objective-C. Why would anyone want to program in a language that effectively is only popular on one platform? Why would anyone want to use a closed framework that’s bound to a single platform?”
Cocoa is an implementation of the OpenStep specification. It’s cross-platform. Right now Cocoa apps can run on Mac OSX or Linux with little change necessary, and hopefully the Gnustep platform can be made to compile on Windows.
This is not always true, sometimes a pure GC is more efficient.
I agree … <u>sometimes</u> it is more efficient.
“Cocoa is an implementation of the OpenStep specification. It’s cross-platform. Right now Cocoa apps can run on Mac OSX or Linux with little change necessary, and hopefully the Gnustep platform can be made to compile on Windows.”
That’s great but I just don’t see developers embracing it en masse when Microsoft, Sun, and IBM are pitching a simpler development paradigm – which truly applies to 95% of application development requirements out there. Very few apps need such fine control over system resources these days because it’s far less expensive to scale up than it is to write such concise applications (that’s not to say that some apps wouldn’t benefit from it). If you look at how companies are spending money right now, you’ll note that it’s on creative integration and scaling (up or out). Few, if any companies, are switching from VB, Java, or .NET to C, C++, or Objective-C. That’s all I was saying. 😉
Aaahhh! I did forget that I need to retain the calendar and color objects since they were already autoreleased. Yes, I didn’t go too much into the fact that convention dictates, for the most part, that new objects returned by convenience class methods have been autoreleased. I’ll make sure I fix this right away, along with the missing dealloc message that should be sent to the superclass after the instance variables have been released.
Thanks everyone for catching these mistakes!
Jared
“It’s cross-platform. Right now Cocoa apps can run on Mac OSX or Linux with little change necessary, and hopefully the Gnustep platform can be made to compile on Windows.”
This is a real question:
Would it help if Apple started really pushing cross platform Cocoa (openstep?) programming tools for other platforms? Would it be helpfull to all *NIX environments if they all shared this common approach?
I have a hard time imagining developers embracing Cocoa, let alone Objective-C. Why would anyone want to program in a language that effectively is only popular on one platform? Why would anyone want to use a closed framework that’s bound to a single platform?
I have a hard time imagining developers embracing MFC… why would anyone want to use a closed framework that is bound to a single platform?
Look, I’m all for cross-platform solutions, but using things like Swing/Qt/etc is a tradeoff. You usually can’t access all of the GUI functionality of the platform, and its often obvious that your product isn’t a “native” application.
What most large applications do is keep the back-end code in ANSI C/C++, then use native toolkits for each platform GUI. So in OS X, the GUI would be in ObjC + Cocoa. In Windows, it would be in MFC. The beauty of ObjC + Cocoa is in just how quickly you can create a fully-functioning GUI and integrate it with the rest of your app.
And for the posters interested in Java: Apple provides Java bindings to Cocoa. It’s built into their tools, so when you write a Java app, you can forgo swing for Cocoa if you want (again, to get a real native feel for the app… or if you just prefer Java over C/ObjC).
what is far more important than the language (considering it has some “common” features like Objects support, of course), is the quality of the development framework and perhaps the developpers tools. And honnestly, OpenStep is way ahead if you considere quality, consistency, elegance and ease of use. I don’t even speak about InterfaceBuilder (or Gorm in the case of GNUstep) for creating GUI.
It’s a truely wonderful framework. You develop way more quickly with it …
Reference counting isn’t very difficult to use… there are some simple rules to follow , of course, but frankly it’s not a so big annoying point (in fact for many people it’s even a plus !). Good case study, GNUstep supports the use of a garbage collector instead of the retain/release … but almost any GNUstep programmers/programs uses retain/release (the only exception is GNUstepWeb which uses in some parts of it garbage collecting).
see http://www.stepwise.com/Articles/Technical/HoldMe.html
for a good article on retain/release.
Don’t focuses on retain/release, it’s not worth it, and you’ll miss the quality of OpenStep …
This series has been quite informative thus far, and has helped untangle some of the issues that have thus far kept me from getting anywhere with PB, IB, AppleScript Studio, etc.
You’ve cleared up some of the weirdness of ObjC syntax admirably. Now, if you can only help me understand how
to apply weird ObjC syntax to actually attaching methods to widgets (The connection between IB connections and the real code in PB?)
Either way,
Thanks
Hi folks,
The memory mistakes in my code have been fixed (along with some of the explanations), but I didn’t convey the placement of the fixed paragraphs properly to the editor, so right now it’s all a bit mixed up. But it’s being taken care of right now, so, hopefully soon, everything will look right.
Sorry about that,
Jared
If one is able to fix OS X .pbproj files to original .project files, then one is effectively able to run the same code on OPENSTEP, thus crossplatform to Intel, Moto, HP and Sparc architectures as well. Without the .pbproj conversion, you could still recreate the project yourselves: the codefiles are quite compatible if you don’t use the Cocoa proprietary objects (which there aren’t many)