Mac OS X Developer's Guide
This Page Intentionally Left Blank
Mac OS X Developer's Guide
Jesse Feiler
MORGAN KAUFMANN PUBLISHERS
A N I M P R I N T OF ELSEVIER S C I E N C E
SAN FRANCISCO SAN DlEGO NEW YORK BOSTON
LONDON SYDNEY TOKYO
Acquisitions Editor Tim Cox
Publishing Services Manager Victor Curran
Senior Production Editor Julie Bolduc
Production Coordinator Mei Levenson
Editorial Coordinator Stacie Pierce
Cover Design Laurie Anderson
Copyeditor Jill Hobbs
Printer Graphic Services
This book was typeset by the author using FrameMaker.
Designations used by companies to distinguish their products are often claimed as
trademarks or registered trademarks. In all instances in which Morgan Kaufmann Pub-
lishers is aware of a claim, the product names appear in initial capital or all capital let-
ters. Readers, however, should contact the appropriate companies for more complete
information regarding trademarks and registration.
Morgan Kaufmann Publishers
340 Pine Street, Sixth Floor, San Francisco, CA 94104-3205, USA
http://www.mkp.com
ACADEMIC PRESS
A Division of Harcourt, Inc.
525 B Street, Suite 1900, San Diego, CA 92101-4495, USA
h ttp ://www.academ icpress, com
Academic Press
Harcourt Place, 32 Jamestown Road, London, NW1 7BY, United Kingdom
http://wurw.academicpress.com
9 2002 by Academic Press
All rights reserved
Printed in the United States of America
06 05 04 03 02 5 4 3 2
No part of this publication may be reproduced, stored in a retrieval system, or transmit-
ted in any form or by any means---electronic, mechanical, photocopying, or otherwise
without the prior written permission of the publisher.
Library of Congress Cataloging-in-Publication Data is available for this book
ISBN: 0-12-251341-X
This book is printed on acid-free paper.
This Page Intentionally Left Blank
When the first Mac OS shipped with the first Macintosh com-
puter in 1984, the development environment was a Lisa com-
puter. No compilers existed on the first Macintosh computers
when they shipped. Much has changed in the almost two de-
cades since then. The first copies of Mac OS X shipped in the
spring of 2001 with compilers for C, C++, Objective-C, and Ja-
va. Apple's integrated development environment featuring
Project Builder and Interface Builder was also on the CD, and
third party products such as CodeWarrior were also available
from the first day.
Born into a mature development environment, Mac OS X pro-
vides new and exciting opportunities for developers of all
sorts to explore the possibilities of personal computing. This
book provides an introduction to those possibilities.
You will find the background of Mac OS X in Part I, including
the architectural features of Mac OS X along with introduc-
tions to its various languages and frameworks. Part II focuses
on developing projects: It explores Project Builder, Interface
Builder, development techniques, and issues related to pro-
viding help and packing your software. Part III looks closely
at code: It hones in on particular tasks that you need to do and
provides line-by-line analysis of the code you will use.
The book looks primarily at the Cocoa framework using its
two languages (Java and Objective-C) equally in the exam-
ples. A lot of space is also given to Carbon, the other major de-
velopment framework that is unique to Mac OS X. Examples
for Carbon are provided in C++.
There are two other significant development environments
that matter on Mac OS X: Java and UNIX. Both are covered ex-
tensively in other books, as they are not unique to Mac OS X.
It is important to note how easy it is to use both of them. In
particular, integration of UNIX command line processing is a
great opportunity for developers. Using the s y s t e m ( ) func-
tion, you can add calls to the command line to any C-based
application (Objective-C, C++, or C). Thus, you can use the so-
phisticated interface development tools such as Interface
Builder to create a spiffy front-end to these critical UNIX-
based tools: That, in large part, is what Apple expects many
developers to do. The opportunities there are enormous, and
the amount of work involved for each one is low.
Major features of the new Aqua interface are dealt with: You
will find drawers and toolbars described, and the implemen-
tation code for them is provided. Services, too, are given a lot
of space, in view of the fact that they represent yet another
area in which individual developers can significantly lever-
age their own work and that of others.
This book refers to an actual program written using Cocoa in
both Java and Objective-C. Called Diary, it implements a basic
journal that can contain various entries and images. You can
download the application and the source code from h t t p : / /
www.philmontmill.com (go to the Mac OS X area). The full
code is not repeated in this book, but major sections of it are
presented and annotated. These sections implement the func-
tionality that many Mac OS X applications use.
For common features that are not used in Diary (drawing, for
example), code from the Mac OS X Developer CD is u s e d ~
Sketch, in most cases.
Apple provides a great deal of documentation on its Web site,
on the Developer CD, and as printed materials that you can
purchase. Of particular interest are the Project Builder exam-
ples that are installed with Project Builder. The step-by-step
tutorials for Interface Builder and Project Builder walk you
through many of the processes described here.
In addition to the step-by-step tutorials that Apple provides
in several media, there also is definitive and encyclopedic
documentation of Mac OS X APIs available online and with
the Developer CD. As new features are added to the Mac OS
X APIs, sometimes the documentation lags behind the code a
little bit: If you do not find what you are looking for, check
back later.
Rather than duplicate Apple's documentation, this book at-
tempts to provide alternative perspectives in order to provide
a well-rounded view of the technology.
Apple's Web site is an essential resource for all developers.
Located at http://developer.apple.com, it provides sample
code, technical documentation in a variety of formats, and in-
formation about Apple and third-party resources including
training, consulting, and publications.
In addition to the developer site, the support discussions at
h t t p : / / w w w . a p p l e . c o m / s u p p o r t can be of help to develop-
ers. Sections devoted to developers contain exchanges that
may provide you with information and tips; you can also post
your comments and questions there.
Mailing lists are available through http://www.lists.ap-
ple.com. These lists include announcements as well as discus-
sion lists of interest to developers, including lists devoted to
Project Builder, Cocoa, Carbon, and Java. Most of the lists are
managed by Apple, but some third-party lists are also includ-
ed.
Finally, the author's Web site at http://www.philmont-
mill.com contains a section devoted to Mac OS X. It provides
a question and answer forum as well as a section with post-
ings of information relevant to Mac OS X.
Many people have contributed to this book. At Morgan Kauf-
mann in San Francisco, Tim Cox and Stacie Pierce provided
strong editorial guidance, while Mei Levenson and Laurie
Anderson did great work on designing the cover. Sheri
Dean's help on marketing is always terrific. In Boston at Aca-
demic Press, Julie Bolduc, production editor, and Jill Hobbs,
copy editor, worked wonders with a very complex manu-
script and a very tight deadline.
Notwithstanding the assistance of all of these people, any er-
rors that remain are the author's handiwork alone.
Mac OS X, the new operating system from Apple Computer, is built
on firm foundations. These include the principles of modern operat-
ing systems (including multithreading, multiprocessing, a UNIX-
based kernel, and memory protection) as well as object-oriented pro-
gramming and component software.
This part of the book provides a summary of the Mac OS X architec-
ture, as well as the principles of modern operating systems and ob-
ject-oriented programming.
This Page Intentionally Left Blank
Mac OS X is a departure from previous operating systems both on
mainframes and on personal computers. Its structure is thoroughly
modern~it is based on a small kernel that isolates the most critical
aspects of the operating system, and it is object oriented to a degree
that has not been seen in a mainstream operating system. Its user ex-
perience has been developed based not only on Apple's years of re-
search and development in this area, but also on the powerful
processors of today and tomorrow that can provide a rich, sophisti-
cated, and delightful user experience of greater elegance and power
than their earlier incarnations could provide.
This book is for Mac OS X developers~for people who are starting
to explore Mac OS X to find out what's there and what the opportu-
nities are. It is about writing software and about how Mac OS X
makes the developer's job much easier---and very different.
Writing computer software can be very rewarding~both intellectu-
ally and financially. Yet it requires scrupulous attention to detail
and often consists of continuing repetitions of nearly similar tasks~
tasks that must be carried out with attention and accuracy, despite
their likenesses. Errors can cause immediate problems, or they can
lie in wait until a particular combination of circumstances conspires
to loose their destructive forces on unsuspecting people.
The work is extraordinarily labor intensive, consuming large
amounts of the lives of often highly paid people while requiring them
to repeat (not mindlessly but mindfully) the same tasks over and
over, at the same time exacting high prices for even the slightest
flaws or inattention to these complex, repetitive processes.
For nearly 50 years, people have looked at the process of program-
ming computers and tried to improve it. The impetus for these at-
tempts comes from programmers themselves as well as from their
managers. Management, of course, would like to reduce costs, im-
prove the reliability of code, and produce software more quickly.
These incentives are nothing compared to the goals of program-
mers~people who find themselves writing sort routines, natural
language parsers, report formatters, and mouse-tracking procedures
over and over and over again. Each version is almost like the last
one--similar enough to pose little imaginative challenge, yet differ-
ent enough to be riddled with snares for the inattentive.
Meanwhile, the nature of computer software has been changing,
with the focus moving from mainframes to personal computers and
then to networks of machines. As the nature of software has changed,
enormous advances in hardware (processing speed, memory, and
storage) coupled with dramatic decreases in their costs have allowed
developers to experiment with new techniques that previously
would have been impractical to implement.
This chapter addresses three basic issues that are at the core of Mac
OS X development:
9 Who is a programmer?
9 The search for better ways to write software
9 The evolution of software
Far from being abstract historical issues, these are at the core of the
developer tools and experience in Mac OS X.
Traditionally, there has been an enormous barrier between
programmers and software users. With Mac OS X, that barrier
is being broken down; in fact, it has been wobbling for some
time now. The concept of power users or advanced users has
been around for ages: Macros, Visual Basic scripts, Apple-
Script scripts, and the like are typically written by these peo-
ple. Programs that need compilation, however, have been the
province of programmers. True, some power users have ex-
perimented with them, but by and large, they have stayed
away.
With Mac OS X, the range of programming tools is vast: it
ranges from the command line that is available in Terminal,
through scripting technologies such as AppleScript and Perl,
and on to services (which allow for the construction of very
customized programs and processes). Also, the development
tools~compilers, Project Builder, and Interface Builder~are
distributed with shrink-wrapped copies of Mac OS X and are
easily downloadable from Apple's developer site located at
(http://developer.apple.com). Apple is making it easier to
program, and it is making those tools more widely available.
The bulk of programming is done not for shrink-wrapped
products but for custom applications. Some of these are ex-
tremely tailored: one person writing code for private use. Oth-
ers are written for a particular environment (one school or
office) or for vertical markets (libraries, veterinarians, or
graphic artists).
If you are wondering if you could possibly write a program,
worry no more: You can with Mac OS X. This book helps you
understand the concepts behind developing for Mac OS X.
The development tools that are on the Developer CD as well
as the tools and sample code on Apple's developer site
(www.apple.com/developer) are thorough and informative:
their information is not repeated here to any great extent.
Perhaps more than the economic motives of management, the
sense among many programmers that they are wasting enor-
mous amounts of time repeating and repeating the same old
code has inspired a decades-long search for better ways to de-
velop software.
This search for better ways to write software has centered on
three primary areas:
9 The process of producing code
9 The reuse of existing code
9 The abstraction of code
In this strategy to improve the production of software, the fo-
cus is on the actual production of code. Compilers and code
generators automate its production while techniques of cod-
ing such as structured programming improve the quality of
the code. Nontextual programmer tools bring the power of
graphical user interfaces to programmers (at last!).
today, the possibility of writing a compiler was not widely ac-
cepted in the early 1950s. Compilers and high-level languages
(starting with Fortran, Algol, and Cobol in the late 1950s) have
grown far beyond their early implementations.
The idea of compilers is to allow people to program in ways
that are more natural to them than the peculiar instructions of
individual computers. In 1978, Dr. Grace Hopper, one of the
most important early compiler developers (she led the group
that developed A-0 for the UNIVAC), recalled in an address
on the origins of compilers:
[T]he primary purposes [of building compilers]
were not to develop a programming language, and
we didn't give a hoot about commas and colons ....
We were trying to solve problems and get an-
swel"s ....
We were also endeavoring to provide a means that
people could use, not that programmers or pro-
gramming language designers could use. But rath-
er, plain, ordinary people, who had problems they
wanted to solve. Some were engineers; some were
business people. And we tried to meet the needs of
the various communities. I think we somewhat lost
track of that, too. I'm hoping that the development
of the microcomputer will bring us back to reality
and to recognizing that we have a large variety of
people out there who want to solve problems, some
of whom are symbol-oriented, some of whom are
word-oriented, and that they are going to need dif-
ferent kinds of languages rather than trying to force
them all into the pattern of the mathematical logi-
cian. 1
The "tough-guy" early programmers who struggled with ma-
chine code and then with assembly language often looked
d o w n on the softies who used compilers and high-level lan-
guages. The code generated by compilers was never so effi-
1. History of Programming Languages, Richard L. Wexelblat, editor. Aca-
demic Press, 1981, p. 11. The address was given as the keynote speech
at the ACM SIGPLAN History of Programming Languages Confer-
ence, June 1-3, 1978.
cient as that written directly in assembler or machine code (or
so they said). With today's highly optimized compilers and
blazingly fast processors, such arguments surely have little
basis in practical reality. (But a reminder such as this is always
welcome in some quarters.)
C o d e Generators Code generators represent another ap-
proach to the problem of improving the production of soft-
ware. Code generators~which in fact antedate compilers~
let you specify the nature of the problem you want to solve (a
file to be sorted, a report to be produced, etc.) and they then
produce the code to do the job. This code can be low- or high-
level code, depending on the particular code generator. Some
generators are quite complex~Burroughs Corporation's
LINC system in the 1980s allowed users to specify screen lay-
outs, report formats, and database designs, and it generated
Cobol code as output. The code that is produced can often be
modified manually to fine-tune the end product.
Code generators are a very efficient means of producing basic
code with little customization. Mac OS X's Project Builder and
Interface Builder allow you to create the basic files of an appli-
cation automatically; stubs for classes and methods are gener-
ated automatically as you specify them graphically.
to compilers and code generators, a third technique for im-
proving the production of code was developed early on. It is
in essence the "good faith" efforts of programmers to police
themselves and to write understandable code. Whereas com-
puters and compilers are quite persnickety about the code
they read and are intolerant of even the smallest faux pas,
they have infinite patience when it comes to deciphering the
complexity of the code. People, however, are just the reverse.
In reading code (or any text, for that matter), the eye and brain
often correct minor errors without your noticing it. (That is
why you can so often not find a compiler error that consists of
a single misplaced letter.) By the same token, following a con-
voluted logical process quickly taxes the poor human brain.
Realizing that the challenge is often to produce code that can
easily be read and understood by people (who are modifying
it at some time in the future), programming styles and tech-
niques have been developed to make it easier for people to
read code.
These techniques include the notion of structured program-
ming (from which go to statements are banished) and more
recently the development of object-oriented programming
(from which conditional statements are largely excluded).
The results of these two stylistic decisions are programs that
consist largely of declarative statements that are executed se-
quentially in the same way each time. Such programs are
much easier to write and debug than they would otherwise
be.
get to use the fruits of their own labors. Recognized produc-
tivity improvements for end users such as databases and
graphical user interfaces have been slow in coming to the pro-
grammer's environment. With Mac OS X, developers will find
an environment that is heavily graphically oriented. Other en-
vironments have provided more or less successful interfaces
to text-based tools; with Interface Builder, you will find a true
graphical programming tool. And because its primary pur-
pose is to build graphical interfaces, that focus is totally ap-
propriate.
The advantage of reusing code has been obvious to program-
mers for decades. Every programmer has reused code, wheth-
er from a previous project, from a colleague, from code
samples, or from books and magazines.
Reusing code provides obvious and immediate benefits, albeit
at a cost. For code to be reused, it must be directly applicable
to the problem at hand. Routines that calculate mathematical
functions (sines, cosines, etc.) are fairly easy to reuse. As soon
as the code starts to be customized for a specific purpose,
however, its reuse becomes problematic. Of course, it is pre-
cisely such customized code that people want to reuse. Unfor-
tunately, in doing so, all too often the advantage of reusing
old code outweighs the disadvantage of its not being quite
right for the job. More often than not, it is the user who suffers
with an interface that just isn't quite right.
To deal with the problem of reusing code that isn't exactly
right, three approaches have been developed to make the sit-
uation better: parameter-driven code, object-oriented pro-
gramming, and moving commonly-used code into system
software.
factored into functionally separate parts. The interface includ-
ing variables that change from time to time is divorced as
much as possible from the operational side of the program. As
needed, the program queries the interface (or a file) for the pa-
rameters it needs to carry out its work.
The use of resources with the Mac OS is a prime example of
parameter-driven code. The appearance of windows is speci-
fied in resources that can be changed without recompiling the
program itself. Text can be changed from one language to an-
other without touching source code. Over time, even fairly
complex issues such as centering of windows on monitors have
been moved into resources rather than application-specific
code.
In Mac OS X, the parameters and data are located in files of
their own. Whereas on the Mac OS resources often are placed
in the program file, customization and localization in Mac OS
X requires no change at all in the application file.
oriented programming as an issue of programming style as
well as a strategy for reusing code. It allows the reuse of exist-
ing code while allowing its modification (overriding). The
modification of preexisting code can be done at compile time
as well as at run time with dynamic linking.
Frameworks extend the benefits of object-oriented program-
ming into a more generalized sphere. Until recently, frame-
works were viewed much as high-level languages, databases,
and compilers were seen by assembly-language program-
mers. They were considered inefficient tools for sissies who
didn't want to do "real" programming. Of course, nothing
could be further from the truth, and programmers (and man-
agers) gradually became aware that there were large sections
of critical pieces of software that duplicated one another and
that were so patched up that it was almost suicidal to make
any changes to them. The issue today with regard to frame-
works is which one to use, not whether to use one.
System Software One final approach to reusing code is the
gradual incorporation of common functionality into the oper-
ating system. Originally, operating systems provided the
minimal functionality necessary to run application programs
on a computer. Gradually, functions that were w r i t t e n ~ o v e r
and over--by application programmers have migrated to the
system software level.
Thus, in mature operating systems, programmers can expect
to find utility routines that manage arithmetic, trigonometric,
and date functions. Communications between and among
programs and computers are managed increasingly by the
system software and not by the programs themselves.
The last main approach to improving the development of soft-
ware has been the increasing use of abstraction. Initially, com-
puter code had to be written for the specific computer on
which it was to be run. Even as late as the 1960s, programmers
needed to know the identifying number of the tape drive used
for standard input on their computer and the number of the
tape drive used for standard output. Programs written for a
computer whose tape drives were numbered differently
would not run.
From the earliest days of computing, people realized that by
providing an abstract concept of a "virtual machine" or a
"pseudo-machine," code could be written to interact with
these imaginary machines~and at run time an operating sys-
tem could concretize the code to the machine on which it was
running. This abstraction meant that programmers needed to
learn how to write for the abstract machine (a general con-
cept) rather than for individual machines.
The cost of abstraction lies in the additional work that the op-
erating system must do at run time to concretize the code. As
the power of computers has dramatically increased, this cost
has been worth bearing~particularly when weighed against
the advantages derived from allowing programmers to write
in a more general way. In Mac OS X, the architecture of the
system (which incorporates an abstraction away from the
hardware layer) is based on the notion of hardware-indepen-
dent abstractions; no additional run-time cost is incurred.
While people have been dealing with the issues surrounding
improvements in the production of software, the nature of
software has changed. In response to the development of per-
sonal computers and the rise of networking (including the use
of the Internet), the nature of software has changed substan-
tially.
Along with the increasing power of computers, the complex-
ity of commonly used software has increased. The increasing
complexity of software is not merely a problem for users; for
developers it has become a nightmare. As many applications
have encompassed more and more functionality (often far be-
yond what their original designs considered), the code has be-
come more fragile with each additional modification.
The computer revolution is just about over. Ninety-two per-
cent of Americans under age 60 have used a computer; 75%
percent of them have used the Internet; and 67% have sent at
least one email message. A whopping 81% regularly use a
computer at home or at work. 2
Many of these people use computers only sporadically~for
periodic word processing, to access the Internet, or to do
bookkeeping. Only a relatively few people actually use com-
puters routinely and regularly throughout the day. Most com-
puters today are woefully underutilized, yet few of their users
would willingly increase their use of the machines.
It has been suggested that all the major software that needs to
be written has already been produced. Word processing,
spreadsheets, communications, bookkeeping, databases,
desktop publishing, etc.~sometimes it seems as if only rela-
tively minor enhancements (and simplifications!) are needed
in these categories. From this point of view, new software will
follow along in these molds, customizing data structures, be-
ing applied to specific markets, and otherwise being refined~
but staying the way that it is.
2. The National Public Radio~Kaiser Family Foundation~Kennedy School of
Government Survey of Americans on Technology. Surveyconducted in No-
vember and December, 1999. http://www.kff.org/content/2000/
20000228a.
On the other hand, many people see an industry just waiting
to take off. It is hard to underestimate the deleterious effects
of the crisis in development of the mid-1990s. Software is just
too complicated to produce in anything like a timely, efficient,
and cost-effective m a n n e r ~ a t least using the old techniques.
With a solution on the horizon for the difficulties of develop-
ing software, and with the dramatically increased power of
computers, the software industry could indeed take off.., but
to where?
Software and t h e Internet The Internet is everyone's favorite
destination these days, and its effects on the world of software
can scarcely be overestimated. Internet protocols are relative-
ly simple, yet they allow people to communicate and to share
information with little difficulty. The computer industry has
seen in the Internet a way to disseminate information about
its products quickly and to provide technical support to be-
wildered users (who are not quite so bewildered that they
can't get to the Internet).
The Internet is also seen by many as a marketplace~a tool
that can deliver digital products almost instantaneously any-
where in the world. Not surprisingly, one of the first digital
products to be sold over the Internet was software.
Perhaps the Internet's greatest influence is, in a perverse way,
due to its simplicity. People stymied by their word processors
are finally getting up the nerve to say, "If I can connect to a
computer halfway around the world, why can't I get a header
to print on my report?"
Empowered by their connections to remote computers, they
are starting to realize that the problem with printing headers
might actually not be their fault~the software might be too
complex. How few programmers realized that empowering
the masses to surf the Net with a click of a mouse would turn
people into demanding users, no longer content to adjust
their activities to the arbitrary restrictions of computer soft-
ware.
Activity-Centered Computing Increasingly, the focus of soft-
ware developers is on people and the activities that they are
carrying out with the aid (and occasionally the hindrance) of
their computers. As computer software addresses more and
more routine and mundane aspects of people's lives, the re-
luctance to invest substantial amounts of time and money in
learning how to use the software grows.
The meadows of pastel notes taped to the sides of monitors
around the world testify to the fact that it remains simpler to
write a m e m o r a n d u m on a scrap of paper than to use a com-
puter as an aide-mdmoire. Any hope of expanding the market
for computers and software must rely on increasing the sim-
plicity of software products. It is true that the big things are
done (probably), but the myriad pesky details of life with
which a computer could assist with remain. And until they
are easier to handle using a computer, people will continue to
save scraps of annotated paper, tape notes to doors, and keep
an extra sum in their checking account to avoid having to
strike a balance once a month.
One of the biggest areas of
growth in the software industry for the twenty-first century is
in all of those domains that remain relatively untouched by
today's software products. Computers and software have
found a place in offices and workplaces; in homes, they have
become established in the office-like activities of a home (ev-
erything from a home business, to personal accounting, to the
office-like activities of students preparing research papers).
A relatively small market does exist for computer games and
diversions~but often these remain in the office mode. The
vast range of activities that could use an assist from comput-
ers but that are carried on in places too noisy or dirty for com-
puters (garages and workshops), or in places too dignified
and quiet for computers, represent a vast untapped market
for computers and their software.
The computer industry has learned how to put computers on
desktops and on the laps of business travelers. It is taking the
first few baby steps toward putting computers in briefcases,
backpacks, and purses. The software that will help the indus-
try break out of its relatively confined mold (and will provide
fame and fortune for its developers and promoters) must also
break out of the office model.
The U.S. Federal Communications Commission has estimated
that two-thirds of the people alive today have never placed a
telephone call. When considering the opportunities for com-
puters, remember this point. You may be looking at a market
that is close to being saturated in a very few areas of relative
wealth and sophistication, but there is an almost unimagin-
able market out there for software that does the things the
vast majority of the Earth's population want to do.
grown up to a certain extent with the growing up of the com-
puter industry. In its evolution and development, the indus-
try has provided ever-richer data types and more powerful
processors. For people who have experienced this process, it
is easy to fall into the trap of thinking that software has be-
come more complex. In fact, it hasn't; the chronology is being
confused with complexity.
Half a century ago, the popular impression of what a comput-
er would be (as seen in the press and movies) included video,
speech recognition and synthesis, and near-instantaneous
communication among people around the world. The avail-
able products, constrained by limitations of existing hard-
ware and software, have fallen far short of those expectations.
Despite having lived through advances of hardware (and the
concomitant reductions in the compromises that users had to
make to deal with the machines), you should remember that
it is the current data types that are natural. Communicating
with anything (person or machine) by typing in only capital
letters (and expressing a gloss on the content by typing marks
of punctuation sideways [:)]) is unnatural and confusing. The
so-called advanced technologies are the basic ones.
Graphics aren't decoration; multimedia isn't optional. They
are parts of our lives~and have been for millennia. Anyone
who feels that all the basic software has been written is living
in a two-dimensional, text-based world that is very quiet and
still. Adventuresome people and those whose jobs have re-
quired assistance from computers have adapted to live in that
world. These people constitute only one-third of the popula-
tion of the United States (and for many of them, their patience
is wearing thin). In fact, there is a grain of truth to the notion
that all the major software has already been written. It is high-
ly likely that all the major software of the old kind has been
written. The software for the vast majority of people in the
world has yet to be written. It requires new ways of thinking
about software and its development, and it requires a new
tool.
C o c o a Cocoa is the basic framework that provides a robust,
powerful, development environment with the tools needed to
develop for Mac OS X. You use Objective-C or Java (or both)
to program in Cocoa.
For some, it will be your first experience with using an object-
oriented framework. Still others will be exploring the world of
object-oriented programming for the first time.
Object-oriented programming and reusable frameworks are
sophisticated concepts that ultimately make the job of devel-
o p i n g ~ a n d maintaining~software easier. Remember, how-
ever, that the more new concepts you have to learn with
Cocoa, the longer it may take.
The biggest challenge most programmers have in learning to
use a framework such as Cocoa is learning to trust it. It's there
to be u s e d ~ a n d while at first it may seem easier to go off and
write some code of your own, in the long run it makes great
sense to take a moment and see if Cocoa already has code to
do what you want to do.
Almost all experienced programmers taking a one-week in-
troductory course in MacApp exhibit similar behavior. On the
first two days, they roll their eyes and complain about having
to use the "complicated" framework. Instead of being al-
lowed to write a dozen lines of code, they complain, they are
forced to look through the framework to find the classes to
use and the methods to override. All of this is woefully ineffi-
cient (they say).
Sometime during the third day of most introductory MacApp
classes, the experienced programmers get very quiet. As the
examples get more complex and the lab exercises become
closer to real-life situations, a hush generally descends on the
class. And then things start to get noisy again. The program-
mers who were complaining about having to use an "awk-
ward clumsy framework" to do something they could have
done in "a few lines of code" are now excited that by overrid-
ing only one method they are able to implement drag-and-
drop, multiple selections, or undoable commands. It is that
m o m e n t ~ t h e moment when the power of the framework is
u n l o c k e d ~ t h a t convinces people that they are on the right
track.
If you are new to frameworks, remember this idea. It will take
a little while for you to get to the point where you trust the
framework. Once you do, you'll be on the road to a powerful
way to develop the exciting software that is part of the Mac
OS X world.
Carbon Carbon is a shared library that lets you program for
Mac OS X as well as for Mac OS 9 and earlier. You can use C,
C++, or Java to program for Carbon.
If you are starting from scratch, you will normally use Cocoa
unless your application must run on pre-Mac OS X systems. If
you are modifying existing code, modifying it to use the Car-
bon libraries is often easier than rewriting it in Cocoa. On Mac
OS 9, Carbon is not a framework, although there are frame-
works that take advantage of it (such as PowerPlant and
MacApp). On Mac OS X, Carbon is a f r a m e w o r k ~ i n the sense
of that word in the Mac OS X environment (a bundle contain-
ing a shared library and all the headers needed to use it).You
need not write object-oriented code to take advantage of Car-
bon; in fact, you can write perfectly awful spaghetti-code circa
1970 to run against the Carbon libraries (although why you
would want to is unclear).
In this book, Carbon is presented most frequently as a com-
parison to Cocoa. This dual presentation will help you read
and understand Carbon code as you modify it or use it as a
template for Cocoa code.
What matters most about code compiled with the Carbon li-
braries is that they run natively on Mac OS X. Unlike Classic
applications that were written for Mac OS 9 and earlier, they
do not run in the Classic environment. They adopt the Aqua
interface automatically, and they can take advantage of mem-
ory management and stability in Mac OS X.
Mac OS X provides an extraordinary computing experience
for users. Its highly reliable performance is unfortunately a
rarity on the desktop; it is as robust as many high-end main-
frame systems. Its integrated graphics and networking make
a strong statement to users and developers alike: This is a se-
rious, twenty-first century computer.
But there is something else.
The process of developing applications for Mac OS X is unlike
anything else. Developers and programmers get the same
treatment that early users of the Macintosh got: intuitive, sim-
ple, highly productive tools. If you are old enough to remem-
ber typewriters, remember h o w liberating it was to use a
word p r o c e s s o r ~ n o longer did you slow d o w n at the bottom
of a page, living in dread of a typo on the last line that w o u l d
cause you to have to retype the whole page. As you start to de-
velop for Mac OS X, you will experience the same sort of lib-
eration.
The system embodies the contemporary ideas about software
development that have been touched on in this chapter. It is
not Cobol or Assembler hidden under a mask of trendy
b u z z w o r d s ~ i t is new and exciting, and it can help you to re-
member that p r o g r a m m i n g can be fun.
Whether your emphasis is on the act of p r o g r a m m i n g or on
the results that you deliver to your users, you will find the
power of the Mac OS X environment invigorating. You m a y
choose to use that power to drastically shorten your develop-
ment and maintenance c y c l e s ~ o r you may choose to use it to
tackle projects that you never w o u l d have dreamed of doing
before.
Programmers have been among the last to profit from the new
technologies that they themselves develop for others. There
may be a silver lining to that cloud. If you look at the develop-
ment of programs as a generic task, the tools that developers
have for that task are now at least as good a s ~ i f not better
t h a n ~ t h e tools anyone has to do anything on a computer.
This chapter covers the Mac OS X architecture. You can find the
day-to-day record of how Apple arrived at this architecture in old
magazine and newspaper clippings; there were many false leads and
turns in the road at Apple and NeXT as well as throughout the com-
puter industry and academe over the last half-century. At times, the
direction in which the computer world was headed was not clear; in
retrospect, it is possible to trace the evolution of the architecture of
Mac OS X without the digressions and distractions that in fact oc-
curred on the way here.
This coherent story is what actually happened--although few people
realized at the time where the adventure would end up.
21
Operating systems shouldn't be of any concern to end users
and should be of only minimal concern to developers and
programmers. They should just go about their business, keep-
ing the hardware running smoothly and trafficking among
the needs of software.
Of course, the computer world is far from this happy picture.
Operating systems do matter. They not only influence devel-
opers in what and how they develop, but also impinge on us-
ers' consciousness when they get in the way (often by
misbehaving). Precisely because operating systems are not
yet highly developed enough to be invisible (or at least trans-
parent) to developers and users, it does matter what is down
there gurgling at the bottom of your computer.
By the time of the first personal computers, computer operat-
ing systems were highly developed and quite sophisticated.
They were able to manage computers with enormous banks of
disks, endless rows of tape drives, large amounts of memory
(at least for those days), and many simultaneous (or almost si-
multaneous) tasks running under the control of scores of us-
e r s ~ m a n y of whom sat at remote terminals connected via
phone lines from distant locations.
Precious little of this sophistication in operating systems car-
ried over into the early personal computer operating systems.
Personal computers, of course, were an inherently different
type of computer from mainframe time-sharing computers.
Personal computers had no banks of disks~two diskette
drives were a luxury; they had small amounts of memory;
they ran single tasks under the control of one person~hence
the term "personal computer." Their operating systems,
therefore, had different characteristics, and they were imple-
mented to fulfill the needs of the single-processing, unnet-
worked, desktop world.
As happens with so many things (particularly in the comput-
er industry), time brought change and improvement. The
desktop operating systems evolved just as the computers they
were running on evolved and grew. Today, the desktop per-
sonal computer is likely to be more powerful than the main-
frame of yore, with more memory, more disk storage, and
even faster processors. Like the mainframe of yore, howev-
e r r a n d unlike the personal computer of y o r e ~ i t is likely to
have several processors, be called upon to carry out several
tasks at once, and communicate over a telecommunications
network that is more complex than the mainframe-centric net-
work of two decades ago.
Today's personal computing environment may be more fa-
miliar to the 1980s corporate mainframe programmer than to
a colleague who has grown up totally in the personal comput-
er world. One characteristic of today's environment (and of
the time-sharing environment in the past) is that the computer
resources are shared among many processes and potentially
among many users.
When the computer and its resources are shared, its problems
are also shared. There are times when the computer crashes or
finds itself wandering along some dark and dangerous by-
way. When the computer is not shared, restarting it means
that your unsaved spreadsheet may be lost or that your Inter-
net connection may be broken. In a shared mainframe envi-
ronment, many users' spreadsheets, transactions, databases,
and calculations may be lost; if the computer is serving as a
telecommunications hub (as many mainframes did and do),
hundreds, if not thousands, of network connections may be
b r o k e n - - a n d with them scores more spreadsheets, transac-
tions, databases, and calculations may be lost. Restarting a
shared computer is a Very Big Deal.
You can appreciate this fact when you read on the front page
of your local paper that an Internet access provider's system
has crashed. Programmers from the mainframe era can also
recall the consequences of computer crashes" meetings, retri-
butions, memos, and even dismissals. Restarting a mainframe
computer was not taken lightly.
On a personal computer where many programs may be run-
ning, restarting the computer after it crashes or hangs is
equally disturbing. A user may easily not know what was
running, and an unsaved spreadsheet may not be noticed for
weeks, if not months.
More than anything else, modern operating systems address
the issues involved in sharing a computer's resources among
many users and many programs. Almost everything that
makes an operating system " m o d e r n " ~ a t least in the formu-
lation given h e r e ~ c a n be seen to stem from these needs. As
personal computers get bigger and faster, as people demand
more and more functionality and responsiveness, and as com-
munications among computers become more intricate, the
need for a modern operating system becomes ever greater.
Modern operating systems don't start (or end) with UNIX,
but UNIX certainly is on the scene of a lot of modern operat-
ing systems. Virtually all modern operating systems have
their roots in the great time-sharing operating systems devel-
oped or perfected in the 1970s: IBM's System/360, the Bur-
roughs 5000 mainframe series (and successors), Digital's VAX
computers, and UNIX.
In those days, sharing computer resources was necessary be-
cause they were so expensive and scarce. The advent of per-
sonal computers made these resources relatively inexpensive
and plentiful, so the early personal computer operating sys-
tems didn't need to worry about the sharing aspects of their
predecessors. Before long, however, sharing once again be-
came necessary as users' demands for processing power
made even these plentiful resources once again relatively
scarce. (Why shouldn't you be able to surf the Net, move files
back and forth from a local server, print out a 50-page report,
and check your calendar all at the same time?)
You can view the role of an operating system in a shared en-
vironment as being that of an agent of transition: almost any
programmer of modest skills can develop a simple operating
system that runs one program at a time and manages a limited
amount of m e m o r y (for example, 640K). The operating sys-
tem that shares processing power and other resources may
have this appearance at any given moment, but in fact its
power and innovation must lie in its management of the tran-
sitions between allowing one program access to its resources
at one m o m e n t and allowing another program access to those
resources at another time.
Thus, the modern operating system needs to provide the ba-
sics of all operating systems (access to hardware and other
system resources) as well as tools for managing transitions
that involve the sharing of:
9 Processing power
9 Memory
9 Communications channels
9 Disks and other storage devices
The sharing of these resources is done in the simplest way, al-
though it is relatively expensive in terms of computer power.
Rather than placing a burden on users, operators, or program-
mers to determine what programs can fit together, the com-
puter's operating system gives each program total access to
all resources for finite periods of time. Each program (and us-
er) can then function as if it were running with no other pro-
grams or users, and the resources are shared by being
allocated in toto to a constantly changing collection of pro-
grams and users. 1
The maid to a touring tragedian playing one-night stands
could turn hotel room and dressing room into "homes" in five
m i n u t e s ~ a n d disassemble them equally rapidly, leaving
nothing but the shell of the room while all the makeup, me-
mentos, clothes, hot plates, and ashtrays found their places in
the nooks, crannies, drawers, compartments, and shelves of
the touring trunk. The star entered hotel rooms and dressing
rooms that were always fully furnished and looked as if they
had been that w a y for years. This is basically what an operat-
ing system does as it shares its resources. The operating sys-
tem is responsible for the packing and unpacking of not one,
but every process that is running. The programs, like the
vaudevillians of the past, never see anything but the complete
environment.
1. Some operating systems--particularly on well-endowed main-
framesmactually support a combination of these techniques. The total
pool of resources is subdivided into partitions with programs and us-
ers being assigned to specified partitions within which the rotational
sharing is carried out.
To accomplish this goal, a modern operating system needs to
implement functionality in the following areas:
User-level security must be provided so that data from
one program or user can be identified and restored to
its rightful owner; in addition, the operating system
generally plays favorites. Once it can identify users
(and classes of users) reliably, it can modify its rota-
tion of resources to favor certain ones. Thus, schedul-
ing is intimately connected to security in a modern
operating system.
Process management is needed to enable a process to
be encapsulated in some manner, stored temporarily,
and then restored to the appropriate registers and
storage locations when it is next given the opportunity
to run.
Memory management must be able to handle the rela-
tively large amounts of memory that the system and
process management may require to be allocated and
then periodically stored temporarily on less valuable
devices than memory (such as virtual memory disks).
Some communication mechanism is needed between
and among processes that are "running" on the same
computer but that may be temporarily inactive and
not in memory.
Exception and fault handling techniques complete the
basic list of modern operating system essentials by
limiting damage to the smallest possible area so that
shared resources are unaffected by a single process's
failure.
As noted previously, there are many other services that any
operating system must perform. The functions mentioned
here are the most critical ones that a modern operating system
must p e r f o r m ~ u s u a l l y over and above the services found in
other types of operating systems. Experience (often painful!)
has shown that these features must be built into an operating
system at its most basic level; attempts to retrofit existing op-
erating systems have proven costly failures.
It is hard to overemphasize the importance of security in mak-
ing a time-sharing system work. Because all operating sys-
tems are responsible for managing input and output to and
from files, terminals, and other devices, they in fact can inter-
cept every single byte or character that is read or written.
Moreover, because a time-sharing operating system must pe-
riodically pack up each program's entire operating environ-
m e n t ~ i n c l u d i n g values stored in memory that are never read
or written to disk ~ i t has access to absolutely everything that
a program touches.
Thus, a modern operating system has a concept of security
that involves individual users with passwords as well as at
least a superuser with access to everything. (There may be in-
termediate levels of privileged users with increasing access.)
Implementing security on personal computers has always
been a problem, because it has traditionally been done as an
add-on. The fact that you can boot most computers from a dis-
kette means that almost all security mechanisms can be by-
passed if you have the appropriate diskette and access to the
drive itself.
The ability to know who is using the computer is important
for more than just security reasons: Many computers are
shared in classrooms, offices, and homes. As users are increas-
ingly able to customize their computing environments, it be-
comes essential to be able to tell who the current user is so that
the appropriate interface can be presented. Without the con-
cept of logging into a computer (and its parallel notion of the
ability to automatically log out a user after a specified period
of inactivity), no practical security exists. A glimpse at the
monitors of computers in almost any computer store will
demonstrate the problems involved in not providing log in
and automatic log out mechanisms.
W h y It Matters Security is important not just to identify the
current user of the computer, but to prepare the computer
(and its current user) for access to networked resources.
Process management is the heart of a modern operating sys-
t e m ~ i t is the core of the packing and unpacking mentioned
previously. A computer program that is running on a modern
operating system should not be aware that it is doing any-
thing but running alone on a single-user computer.
In Mac OS (as in many operating systems), programs can be
suspended whenever they temporarily p a u s e ~ u s u a l l y by
service other processes. However, if a program does not call
W a i t N e x t E v e n r or G e t N e x t E v e n t , the operating system
never has a chance to intervene. Thus, lengthy procedures in
which the program does not need to poll for mouse, key-
board, or menu events can grab hold of the processor and not
let it go--sometimes for very long periods of time. Examples
of such programs are disk utilities that may be checking every
sector of a hard disk for quite some time, installers and com-
pression/decompression utilities, and major calculation
beasts. The damage (that is, the problem of not letting other
applications use the processor) can be mitigated by not letting
other applications run at the same time. In fact, many install-
ers and some disk utilities enforce this restriction before start-
ing their work.
Furthermore, Mac OS supports only multithreading rather
than full-fledged multitasking. In a multithreaded environ-
ment, memory is not moved and the individual threads have
access at times to other threads' data. (Threads are sometimes
processes but may be smaller units of a single process that le-
gitimately should share data.)
Thus, on traditional operating systems, the sharing of the pro-
cessor requires that programs be written in certain ways (by
calling W a i t N e x t E v e n r or GetNextEvenr periodically so
that the operating system can intervene). In a modern operat-
ing system, this strategy~cooperative multitasking~is re-
placed by symmetrical multitasking in which the operating
system is not thwarted in its sharing mission by the way in
which a program is written. The operating system is capable
of starting and stopping any running process at any moment,
moving its entire environment somewhere, and restoring and
restarting it at will.
this chapter, "program," "application,"
and "process" have loosely been used interchangeably. From
here on, the specific term "process" is used to mean a single
executable software environment with its own code, registers,
memory, and other resources (files, communications chan-
nels, etc.). A simple program is always at least one process.
Later in this chapter, "process" will be redefined and nar-
rowed to mean a Mach task that contains one or more threads.
At this stage, "process" is used in the more general sense that
applies to UNIX and most other operating systems.
Multitasking allows a computer's resources
to be shared among more tasks than one. If all tasks were busy
at all times, there would be little, if any, saving. However, be-
cause most tasks periodically wait on external events (key-
board input, network or disk communications, etc.), that time
can be given to other tasks.
Much more important, however, is the fact that the mecha-
nism by which a task can be stopped, packed up, restored,
and then restarted can be used for more than just sharing a
single set of resources. Nothing says that the task has to be re-
stored to the same environment from which it was removed
(although the environment must be quite similar). In a com-
puter with multiple processors and significant amounts of
memory, the task can be restored to a different processor and
to a different area of m e m o r y ~ p r o v i d e d that its internal
pointers are undisturbed. This provides additional opportu-
nities for optimization and for using increasingly powerful
computers.
The single-process computer (whether an old batch-mode
mainframe or a traditional personal computer) allows the
process that is running to access memory at will. The advent
of virtual memory allowed programs to access more memory
than was physically available with the operating system by
using disk to store the additional memory. However, even un-
der virtual memory, the process has access to all of the
computer's m e m o r y ~ b o t h real and virtual.
Some programs took advantage of this fact. Quite a few early
Mac OS programs (as well as those for other operating sys-
tems) relied on the fact that certain memory addresses con-
tained certain operating system variables~screen size, for
example. Programmers who needed to get this information
simply read it from the appropriate memory location despite
the fact that that memory location logically "belonged" to the
operating system, not to the application program.
Modern memory management involves several features, the
two most important of which are virtual memory and protect-
ed memory (also known as memory protection). Virtual
memory is the same technique that has been around for some
time now (although it is continuously enhanced); memory
protection is the ability to divide the computer's memory into
areas that belong to certain processes (or to the operating sys-
tem) and to prevent other processes from accessing those
memory locations.
Why It Matters Virtual memory is used to support large
memory demands of programs and of the operating system.
Memory protection obviously increases the stability of the en-
tire computer because a single process cannot inadvertently
or otherwise access other processes' memory locations.
In many traditional personal computer operating systems, ap-
plications can read and write from and to memory locations
that are owned by other applications. Some programs take ad-
vantage of this fact to communicate with one another. Clearly
this approach is risky, as changes in memory layouts for one
application program can cause another to behave erratically.
But it is necessary for processes to communicate with one an-
other from time to time. For example, if a single process is di-
vided into multiple subprocesses (threads) to take advantage
of a system's multiprocessing capabilities, the threads need to
be able to share data, status, etc.~particularly if the process is
going to use any mechanism at all to allow semi-concurrent
access to data. For threads within a single process, the solu-
tion is to access shared data locations that legitimately are vis-
ible to all threads. For processes that do not share memory
locations~and that are prevented from looking into one an-
other's memory locations by a memory protection mecha-
n i s m ~ i t is necessary for them to be able to communicate by
sending messages to one another.
A modern messaging system allows processes to find one an-
other, identify one another, and to acknowledge, receive, and
send messages according to their own internal formats.
In addition to providing solutions to the
problems posed in this section, modern interprocess messag-
ing lays the g r o u n d w o r k for messaging between and among
processes on different computers (e.g., over the Internet).
Failure and exception handling returns full circle to the issue
of security, which started this section on modern operating
system attributes. Like security, robust failure and exception
handling makes everything else possible. Having m e m o r y
protection is all well and good, but if a process attempts to ac-
cess another process's memory, is rebuffed, and then causes
the operating system to crash, you are no better off than if it
had been able to access the off-limits memory, proceeded to
corrupt it, and caused a crash at some point in the future.
Modern operating systems manage failure and exceptions
both within their processes and for themselves. They should
not crash (as indeed no operating system should).
To deliver an operating system as immune
as possible from its own failures, modern operating system
architectures take advantage of all of these features in a de-
sign called a kernel.
When you have an operating system that can run multiple
processes at more or less the same time, where the processes
can have their own m e m o r y spaces, and where they can com-
municate reliably among one another, you can take m a n y sys-
tem services and run them as separate processes. Modern
operating system architecture splits out functions such as file
management, sophisticated message processing, and user ac-
cess into separate processes that can run either as necessary or
as permanently resident processes that respond to messages
as needed.
In such an architecture, the operating system is first divided
into separate entities that can run in this manner. What is left
is the k e r n e l ~ t h a t part of the operating system that is needed
to enable the others to run. Typically, the kernel provides pro-
cess and memory management as well as basic communica-
tion and input/output services. Everything else can be run as
processes taking advantage of these tools.
Most operating systems themselves are allowed to play by
different rules than applications or user processes. (Operating
systems, for example, are not restricted from reading or writ-
ing memory because they must manage virtual memory and
enforce memory protection.) The kernel is no exception.
The other parts of the operating system, however, can usually
safely run as processes in user space (as opposed to the fewer-
holds-barred kernel space). By placing these processes in user
space with its restrictions, they are less likely to cause system-
wide problems. The strategy is as simple as that of the bank
president's giving the vault combination only to the branch
manager rather than to all employees of the branch. In both
cases, customers would not know the vault combination;
however, by giving only the manager the combination, the
bank is reasonably well protected against employee misbe-
havior and need worry only about the manager.
The preceding part of this chapter outlined the idea of a mod-
ern operating system in general terms. It is safe to say that no
actual operating system exactly implements all of those con-
cepts. Mach~the kernel that is at the heart of Mac OS X~im-
plements most of them.
Mach moves beyond some of the general principles, refining
them and enhancing them to provide even more flexible, ro-
bust, and efficient performance.
The concept of processes (described on page 30) is refined and
extended in Mach. The m o d e r n operating system's process is
split into a single task and one or more threads within that
task. Tasks do not run: Their threads run, with each thread
containing its own execution state. The task owns the com-
mon resources that are available to all threads, including a
single address space in virtual memory. Registers, stack
pointers, program counters, and other elements that control
and record the execution state of a thread belong to the indi-
vidual threads of a task.
Mach's design builds in multiprocessor support from the
start. Threads can run on different processors more or less si-
multaneously: Mach contains the mechanisms to provide syn-
chronism and to prevent threads from running ahead of or
behind others. The design also allows for control (even down
to the task level) of which processor specific threads will run
on and what area of m e m o r y will be used for the task's mem-
ory.
As increasingly powerful and numerous processors show up
in computers, these capabilities become more and more im-
portant.
In addition to Mach's support for sophisticated thread man-
agement, it contains a very flexible m e m o r y management
model based on m e m o r y objects. The management of logical
m e m o r y (as opposed to physical memory) is designed to run
in user space--not in the kernel space. By running in user
space, the virtual m e m o r y module does not have access to
system-level calls and is therefore more robust and less likely
to have adverse effects on anything else that might be run-
ning.
As a developer, you are unlikely to worry about m e m o r y
m a n a g e m e n t in Mach; its architecture allows for sharing of
m e m o r y objects among tasks and indeed for sophisticated
distribution of m e m o r y resources. These capabilities are
among those that are difficult to retrofit, and as you find your-
self needing them it is reassuring to know that they are there.
As software evolves away from the single-processor/single-
process model, communications between and among tasks on
individual computers and across networks become increas-
ingly important. It is hard to overemphasize the value of pow-
erful communication technologies and protocols (the Internet
being perhaps the best example to date). In fact, many would
argue that the greatest benefits that have been derived from
computers in the last 50 years have been due to their network-
ing and communications technologies rather than their com-
putational technologies.
Communications in the world of Mach are managed by ports
and messages. You may be familiar with UNIX pipes, which
are byte streams that can link two processes together; the
Mach mechanism supports message streams, not pipe
streams. As with the task/thread structure and the memory
structure, Mach provides a more structured environment
than some other modern operating systems.
Ports are created inside the kernel; they are owned by individ-
ual tasks and, like all task resources, are available to all of the
threads within that task. A thread can communicate with a
thread in another task through the port that they both can see.
Just as with process (task/thread) management and memory
management, the communications infrastructure is designed
to work in an environment of multiple processors and equally
well within a single computer or over a network.
The Mach kernel is designed to manage multiprocessor and
distributed operations. Wherever possible, operating system
functions have been moved into tasks that run in user space
(rather than in the fewer-holds-barred kernel space). This pro-
vides increased stability for the system.
Among user space tasks, Mach has always been planned to be
able to support UNIX, MS-DOS, and other operating systems
running as user tasks. This ability to be able to run a number
of operating systems on top of the kernel was one of Mach's
original goals.
The first computers had no operating systems. They were
rooms full of electronic components that were programmed
with circuit boards and switches, many of which had to be set
by hand. Management of the computer and its resources was
done by someone armed with a sign-up sheet; bills for the use
of the machine were sent out by a secretary. A single applica-
tion program ran the computer and did whatever it wanted to
do, as shown schematically in Figure 2-1. The functionality
delivered to the user consisted of the application and the
h a r d w a r e ~ t h e total area within the two boxes.
Operating systems evolved for a number of reasons~sched-
uling and billing for computer resources being among the pri-
mary ones. As it became possible for computers to run more
than one job at a time, this feat of time-sharing was accom-
plished with operating systems. And so, by the end of the
1960s, operating systems were born out of the necessities to
schedule, share, and bill for computer resources.
Figure 2-2 presents a schematic of the computer environment
at this time: the computer hardware, an operating system,
and, within the operating system, an individual application
program.
similar conceptual scale. Note that the application shown in
Figure 2-2 is smaller than the single application in Figure 2-1,
which had to do everything. Notice also in Figure 2-2 that the
total functionality that could be provided to users is larger
than that in Figure 2-1. The OS itself provides functionality
(albeit in the early days limited); that functionality falls into
three general areas:
0 The OS can take advantage of economies of scale in
development and deployment; code that otherwise
would have had to be written inside individual appli-
cations (if it had been written at all) can now be writ-
ten once and shared by various applications. For
example, starting in very early times, application pro-
grammers left the mechanics of positioning tape and
disk drives to the operating system. For this reason,
the individual applications are smaller.
0 The OS itself can provide direct services to the user:
billing and scheduling of time-sharing jobs were some
of the first. Thus, the total box of services encompass-
ing both application programs and OS suggests more
functionality than was provided by the single applica-
tion program shown in Figure 2-1.
0 The OS provides services to itself that only it needs.
This is usually a significant chunk of the processing of
the OS. Operating systems are voracious consumers of
computer resources in many environments. Main-
frame systems running time-sharing often spend well
over 50% of their processing power managing the OS
itself.
With operating systems such as these, it was possible to run
several application programs at the same time, as shown in
Figure 2-3.
The operating system has grown compared with the early one
shown in Figure 2-2. Note also that the application program
on the right has grown in size. Adding functionality is not
confined to operating systems~users of programs want and
need new features, too. Here a specific type of new function-
ality has been a d d e d ~ a sophisticated interface to the pro-
gram.
Added processing power made it possible to write more so-
phisticated user interfaces; the increasing numbers of people
using computers made such interfaces necessary. With the ad-
vent of graphical user interfaces and the widespread deploy-
ment of the Macintosh computer, people began to appreciate
not only the advantages of a graphical user interface, but also
the benefits of a consistent graphical user interface across
many applications. Standards for interfaces were promulgat-
ed and programmers (more or less) tried to adhere to them.
operating systems were relatively unconcerned with the in-
ternals of the applications that they ran. They started and
stopped the jobs, then sent the bills, and that was that.
Operating systems performed another valuable service. With-
out an operating system, the application program itself had to
interact directly with the hardware. Any change to the hard-
w a r e ~ e v e n so slight a change as the renumbering of tape
drives to accommodate a new device--required changing the
programs.
In Figures 2-2 and 2-3, the application programs are removed
from the hardware; under normal circumstances, application
programs communicate with their operating system, which in
turn deals with the hardware. Relatively large changes to the
hardware can be made without having to change the applica-
tion programs.
The boundaries between the objects in these diagrams are like
the Earth's great tectonic plates: There is tremendous pressure
and friction at these points. Two plates in the Earth's crust
may fit together more because of the pressures holding them
in place than because of any simple fit. Geologic events that
are relatively contained within a single plate can be magnified
to catastrophic proportions when they occur at the boundary
between two plates.
Similarly, the boundaries in these diagrams are fraught with
danger. Whereas the application running within an OS may
be relatively immune to changes in the hardware level, the OS
itself, which abuts the hardware level, must change constant-
ly in response to hardware changes. (On very rare occasions
the hardware changes in response to software requirements.)
Thus, although the OS itself normally shields the application
program's structure and code from hardware changes, the
fact that the OS itself must change in response to hardware
changes does mean that the application's environment is at
least potentially disrupted by changes in hardware.
In 1984, the Macintosh presented developers with an environ-
ment like that shown in Figure 2-4.
The interface design and implementation, which in the Figure
2-3 design were done by individual applications if they were
done at all, are now basic parts of the system architecture. By
not relying on individual applications to implement the inter-
face, each application can become smaller (note the relative
decrease in size from the previous diagram). Furthermore, be-
cause the interface itself is a system service, it should be more
consistent. The notion of a single type of interface for the en-
tire environment carries with it significant benefits for end us-
ers in the areas of training, software evaluation, and general
usability.
Remember that every dividing line in Figure 2-4 represents
the computer equivalent of a fault line in the Earth. That is,
pressures build up, and there are periodic cataclysmic shifts
as one or the other side of the line shifts. Compared with Fig-
ure 2-1, there are far more fault lines in Figure 2-4. Changes in
hardware can affect the operating system; changes in the op-
erating system can affect application programs; and changes
in the application programs can affect the interfaces. And just
to make life more interesting, remember that the changes can
move in the other direction: Advances in interface design can
require changes in the operating system, which then require
changes to applications~and sometimes even to hardware.
Changes to application programs come from two primary
sources:
0 Many changes come from changes in user require-
ments or additions to the application's functionality.
Q A significant number of changes come from external
forces in the program's environment~changes in the
operating system are one of the most common causes
of application program changes.
Managing these changes has been a challenge for developers
and managers for many years. Two strategies have been used
repeatedly (and successfully) to address these issues:
II Libraries of common code have been made available
to applications. They let separate programs use and
reuse code that has been developed, tested, and docu-
mented for both programmers and users.
0 Object-oriented programming and reusable frame-
works have allowed applications to be developed as
more manageable collections of objects that can often
be reused. More important, individual objects within
an application can often be replaced with fewer side
effects.
Figure 2-5 displays the applications from Figure 2-4, schemat-
ically showing the one on the left taking advantage of a reus-
able library and the one on the right taking advantage of an
object-oriented framework.
As is common throughout this saga, the application programs
themselves provide greater functionality when they incorpo-
rate either a library or a framework; the specifically written
code, however, is smaller. (This is not a necessary condition,
as nothing prevents you from using a library or a framework
and coming up with a less functional application than you
could otherwise have done. However, this is the most com-
mon scenario.)
If you consider the boundaries between application, operat-
ing system, library, and framework together, there are many,
many fault lines in this diagram. However, although they are
theoretically more prone to disruption, the smaller size of
each of the components suggests that these disruptions may
be less severe than in the earlier diagrams. Certainly in Figure
2-1 (with simply hardware and an application) almost any
change to the hardware is likely to cause some change in the
software.
In the object-oriented world of a framework, there should ex-
ist individual components (such the gray shaded box in Fig-
ure 2-5) that should be relatively easily replaced. Although a
two-dimensional schematic suggests far fewer boundaries
than actually exist, it still stands to reason that a change re-
quiring a modification only to the shaded box should have a
limited effect on the rest of the system.
This has been the popular theory of the past few years. It does
make sense, and people who have used frameworks and li-
braries (particularly shared libraries that can be used by sev-
eral applications at run time) can testify to a very real sense
that they are saving programming effort in the development
and maintenance of their applications.
But the payoff isn't as big as it should be. Something's not
quite right.
Part of the problem with frameworks is that while they do an
excellent job at shielding the custom-written application code
from changes in the operating system and beyond, and al-
though their object-oriented modularity interacts well with
the object-oriented modularity of applications built using
them, the boundary between the world of the objects and the
outside world (the traditional operating system) is a major ob-
stacle. Most operating systems deal with procedure calls and
data structures rather than objects. Frameworks, on the other
hand, live in a world of objects. Every call across that bound-
ary needs to move from one world to the other. And while
there is a reasonable amount of control of changes within the
object-oriented world of a framework and object-oriented ap-
plications, as soon as this boundary to the flat world is
reached, the efficiencies are greatly reduced.
As a result, it is almost impossible for an application frame-
work to keep pace even with one moderately sophisticated
operating system and interface~the flat, native, non-object-
oriented code of the operating system is updated before the
frameworks.
In fact, it is quite rare for a framework to incorporate all of an
operating system's application programming interface (API)
in its classes and methods, much less to keep pace with its
changes. The task is enormous, and it is always faster in any
individual case to code directly to changed platform APIs
than to change the f r a m e w o r k ~ o r to wait for a third-party
vendor to do so.
The solution, of course, is to make the operating system object
oriented itself. Then there would be no need to synchronize
the API changes in the operating system's flat world with
changes to an object-oriented framework: They would be one
and the same.
The fly in this particular ointment, however, is that there is a
certain degree of inefficiency in object-oriented systems. Nor-
mally this is not significant, but an operating system's tasks
are often extremely time critical. This is a risk that few would
be willing to take.
Meanwhile, the notion of a "modern OS" began to take shape
in the minds of many. (See the next chapter for more details.)
One of the notions behind a modern OS is that of a k e r n e l ~ a
very small, fast section of code that does the direct hardware
interaction; the rest of the OS is implemented as services
above the level of the kernel.
If you combine this notion with the issues in the previous sec-
tion, you might see a way out--as did the people at NEXT. The
operating system itself can be split into two parts: one can be
the critical kernel running as fast as it can, and the other can
be an object-oriented OS.
Figure 2-6 presents a schematic of this stage of evolution: the
splitting of the OS into two parts.
Figure 2-7 depicts the basic design of Mac OS X. The core OS
is Darwin, based on Mach 4--a kernel-based m o d e m operat-
ing system that is not object oriented and on the Berkeley
Standard Distribution (BSD) of UNIX.
The platform OS consists of most of Mac OS X. In Apple's di-
agrams, the emphasis is on the presentation technologies,
Quartz, OpenGL, and QuickTime, but a wide variety of other
services are provided here, too.
The Carbon libraries allow applications that may or may not
be object oriented to run within what is basically not an ob-
ject-oriented world. Cocoa is totally object oriented, and its
applications run alongside Carbon applications in Mac OS X.
One other aspect of Mac OS X needs to be added to this dia-
gram: Java. Java occupies a special place because it functions
both as a programming language (you can write Cocoa appli-
cations in Java) and as a self-contained, object-oriented world
(the Java Virtual Machine). Thus, you can add Java as a sec-
ond high-level framework (next to Cocoa); you can also add it
as a Cocoa programming language.
With all the commotion over the importance of a modem op-
erating system, sometimes the jargon gets overpowering and
developers (much less users) are to be forgiven if they react to
these discussions with a modem attack of the vapors.
At its heart, the notion of a modem operating system isn't
some esoteric litmus test as to whether feature A is or is not
supported. The ideas behind modern operating systems fall
into two major categories: ways to improve the performance,
stability, and reliability of today's computers; and ways to be
positioned to exploit the computers of tomorrow, which, with
multiple processors and persistent network connections
(wired and otherwise), offer opportunities and challenges
never seen before.
A firm foundation on a modern operating system is not enough to
make most people confident about putting their development (and
production) money into a programming environment. Half a centu-
ry of software development experience has shown that programs last
much longer than anyone ever predicted. (Much of the problem with
the year 2000 bug came from software written in the 1960s and
1970s that is still in regular use today. When you consider that few
automobiles from that time are still on the road, the longevity of soft-
ware is alternately awe-inspiring and depressing.)
Object-oriented programming is at the heart of Mac OS X. Cocoa it-
self is an object-oriented framework; MacApp, Apple's C++ frame-
work, is a comfortable fixture in the Carbon environment. Cocoa
49
offers the developer a choice of two object-oriented languages: Objec-
tive-C and Java. This chapter provides a very brief overview of ob-
ject-oriented programming from a language-neutral point of view.
It highlights some of the implementational issues that need to be ad-
dressed and which the three languages address in different ways.
Object-oriented programming is one of the technologies that
has been proposed~and adopted~so as to make the process
of creating software easier, faster, and more efficient. (The
other major technologies that have been proposed and adopt-
ed to these ends are structured programming and databases.)
In contrast, some technologies have been proposed and not
adopted widely. Why have CASE (computer-aided software
engineering) tools not been more successful despite a relent-
less flood of promotion? Why have code generators had lim-
ited acceptance? And perhaps the biggest question of all,
Whatever happened to the 1980s grand design methodologies
that promised to take only a few years to completely model an
organization's data needs (during which time, of course,
nothing would change)?
The difference is quite clear, but you must promise not to tell
anyone (because some people might get a little upset). The
tools and techniques that have succeeded are those that pro-
grammers have perceived as making their lives easier. The
tools and techniques that have failed have been those that
management embraced and that programmers didn't particu-
larly understand, appreciate, enjoy, or use.
There is a little-noted measure of a technology's viability in
the programming world: weekend projects. Most program-
mers love to program and to design software. Some augment
their working lives with volunteer work for community orga-
nizations; others steal away on evenings and weekends to
come up with a shareware or freeware product~or even to
work on what just might be the next "killer app." In these
projects, structured programming, databases, and object-ori-
ented programming abound.
To be sure, object-oriented programming and the other major
technologies are found in the largest corporations, and the
most horrible unstructured spaghetti code messes can also be
found in private skunkworks projects. But by and large, these
are the tools that programmers use when they're working for
the most demanding (yet understanding) bosses of all~them-
selves.
Despite a steep learning curve, object-oriented programming
is easier than traditional procedural programming. An appli-
cation is divided into objects that have the characteristics de-
scribed further in this chapter but that have one critically
important feature: They can be totally self-contained.
Totally self-contained entities can be combined into various
combinations in ways that can produce larger and complex
systems that would be prohibitively expensive to produce on
their own. An example from the 1960s was a combination
clothes washer and dryer. Combining the two products into a
single cabinet seemed like an efficiency; in practice, the two
products constantly managed to interfere with one another
and the combination product ended up saving floor space at
the expense of being constantly in need of repair.
From a practical point of view in the world of object-oriented
programming, an object can be left untouched once it has
been developed. Its functionality and interfaces can be frozen,
and it can be used without worrying about its internals. Pro-
cedural languages~even with shared libraries and utility
routines~rarely can provide this degree of isolation.
Of course, these write-once-use-many objects need to be care-
fully designed. You can do many things to break down the
ramparts of self-containment (you can use globals, refer to
other objects about which you make certain assumptions,
etc.). Nevertheless, many object-oriented programmers have
a bag of objects that they drag along from project to project.
Each object can be reused because it is self-contained and ad-
heres to strict programming standards (the programmer's in-
ternalized set of standards). The reality of object-oriented
programming leans toward programmers saving a day here
and a day there by reusing objects that they have written or
used before. The enthusiasm for object-oriented program-
ming comes from programmers having experienced this pro-
cess and being able to testify that it does indeed work.
What has remained elusive, however, is the large-scale payoff
for using object-oriented programming on large systems. On
a daily basis, programmers experience firsthand the benefits
of object-oriented design as they reuse objects. There is also an
almost tangible feeling that the objects that are written anew
will be easier to maintain in place (even if they are never re-
used).
The benefits of object-oriented programming in large systems
depend on the ability to integrate objects written by different
people with vastly different programming standards as well
as on the ability to combine these objects dynamically.
Despite the fact that an object
designed for reuse can (and should) be designed to make as
few assumptions as possible about its environment, many do
make quite a few assumptions. There is not a significant mar-
ket in off-the-shelf objects because they often don't fit together
well. Even the recent enthusiasm over Java applets has not
been able to cover the fact that most Java applets are reusable
only in the contexts for which they have been designed. (Of
course, for those applets that have been designed as buttons
or other controls on Web pages, that context is so widely
available that some reuse is possible.)
Developers and designers pay a great deal of attention to the
inside of objects, but the big payoff in reusability comes when
attention is paid to the outside of the objects~that is, to their
interfaces and to their functional scope. And that is one of the
most important elements of Cocoa.
combining objects, the details often scuttle the ship. Unless
some binary standard is available, objects in different lan-
guages and from different compilers will likely be unable to
be used together. Standards such as CORBA (Common Object
Request Broker Architecture) are available, but in a classic
chicken and egg syndrome, few developers see the need to
adhere to these standards because no one is combining objects
dynamically across m a c h i n e s ~ a n d no one is bothering to try
combining such objects because the standards are not widely
supported.
Part of the attraction of Java is its promise to simplify this
combination of objects at run time across networks. The
crunch is only now coming where it will be seen whether the
full power that can be delivered is demanded by consumers.
Thus, object-oriented programming is liked by programmers,
is supported anecdotally as saving development and mainte-
nance time, and has at least the potential to provide significant
savings in large system development if some standards-relat-
ed issues can be solved.
Many people find object-oriented programming hard to learn;
for others, it's not at all complicated. One of the factors that
contributes to this discrepancy is the fact that some program-
mers can be comfortable only if they understand the entire
program on which they are working. Others are comfortable
working on a part of a program and relying on others to do
the rest.
For programmers who aren't comfortable until they see the
big picture, object-oriented programming may be difficult to
accept. There is always a faster and more efficient way to do
something procedurally--but it is a way that breaks the ob-
ject-oriented design and that requires all future programmers
to also have the big-picture outlook.
Unfortunately, many computer science courses and programs
emphasize the big-picture outlook and encourage students to
develop large applications on their own. The fact that they are
training their students to solve yesterday's problems using
yesterday's technologies should not surprise those who were
themselves taught to solve day-before-yesterday's problems
using day-before-yesterday's technologies.
If you're not interested in learning new technologies and re-
thinking the way you work, object-oriented programming
may not be for you. The demand for programmers is so enor-
mous that there is room for everyone. There's plenty of Cobol
code that needs maintenance, and there's a whole bunch of
PL/1 applications that need to be converted into something--
anything--else.
What, then, is object-oriented programming, in a language-
neutral sense? This section is a brief overview of this concept.
Objects are entities that in some ways are like small programs.
They have their own data and their own functionality--just as
a solitaire or payroll program does.
Data An object can contain data of any kind--integers, float-
ing point numbers, arrays, strings, etc. The data can even con-
sist of other objects. In the strictest (and best) object-oriented
programming, an object never presents its data directly to the
world. You always have to call one of its functions or methods
to get the data.
In other words, even if the object has a data field called "time
started," you access it by calling a routine like G e t T i m e -
S t a r t e d rather than accessing the variable directly. This is
good programming practice even in non-object-oriented pro-
grams.
Data fields may be called fields or values; they may also be
called member values. Some objects have no data fields of
their own.
Alongside its data, an object has routines--
methods or functions~that it can run. You can call these rou-
tines just as you would call routines (methods, functions, sub-
routines, or procedures) in any programming language. You
may also invoke them by sending messages to the object that
cause the appropriate routines to be run.
The distinctions between methods and functions as well as
those between calling routines and sending messages that in-
voke them are semantic in the various object-oriented pro-
gramming languages.
Each specific object that is created is called an in-
stance. For example, you may have 500 instances of the em-
ployee object~one instance corresponding to each employee
in a company.
Each instance shares the names of the data fields and routines
of the object itself, but each instance has its own data values.
The most common usage holds that the class is the
abstract object that is instanfiated in instances. The relation-
ship between classes and noninstantiated objects is different
in the different object-oriented programming languages (but
is quite close).
Programmers often talk interchangeably about instances and
objects (when they mean an object that has been created and
has its own data) as well as about classes and objects (when
they mean the abstract, noninstantiated thing). This impreci-
sion is a minor point because the context is almost always
clear.
You define an object with a class definition that specifies its
variables and methods. You create a specific instantiation of
that object to contain a single set of data.
In a nutshell, that's it. However, there are a few design issues
that are important in all object-oriented programming lan-
guages and that are particularly relevant to Cocoa and Mac
OS X.
An object may be based on another object--may in fact "de-
scend" from that other object. Typically, the descendant in-
herits all of the data fields and member functions of its
ancestor. Thus, if an employee object has an employee ID
field, a descendant of the employee object (hourly employee)
automatically has an employee ID field, just as another de-
scendant (salaried employee) will also have an employee ID
field.
Any instance of the employee object, the hourly employee ob-
ject, or the salaried employee object may use the employee ID
field (subject to some language and scoping constraints).
Similarly, if the employee object has a method called Cal cu-
l a t e P a y C h e c k , each of the descendant objects automatically
has access to that method and may call it (again, subject to
some language and scoping constraints).
An object may reimplement any method that it inherits from
an ancestor. Thus, the salaried employee object may reimple-
ment C a l c u l a t e P a y C h e c k (the method of employee) to re-
turn a value equal to the annual salary divided by 52 (in the
case of weekly pay).
The hourly employee object may reimplement C a l c u l a t e -
P a y C h e c k to return a value equal to the product of its o w n
data fields, hourly rate and hours worked.
In such a scenario, you can instantiate objects of hourly em-
ployee and salaried employee as necessary. As both are de-
scendants of the employee class, they both have a
C a l c u l a t e P a y C h e c k method (although their methods are
different). You can therefore call C a l c u l a t e P a y C h e c k and
rely on each object to carry out the correct behavior.
This is p o l y m o r p h i s m ~ t h e ability of disparate objects to re-
spond appropriately to messages or function calls that call a
common ancestor's routine.
This scenario also demonstrates the use of an abstract super-
class. The employee object m a y be designed never to be in-
stantiated; only its descendants are actually to be instantiated.
Such an abstract superclass contains common routines that
are either stubs (where the subclasses provide their o w n poly-
morphic implementations) or common routines that need no
overrides in the subclasses.
As you can see from this discussion, the terms ancestor and de-
scendant are used interchangeably with superclass and subclass.
An object can contain data in its instance variables. This data
is available subject to certain scoping and language restric-
tions, as previously noted. The most basic restriction is in the
class definition: You m a y declare variables as being public,
private, or protected. Public variables are visible to anyone
w h o uses the object instance and may be referred to directly
according to the appropriate language syntax. Public vari-
ables are second only to global variables in their inappropri-
ateness for use in good code.
Private variables are visible only to instances of this particular
class. Thus a method of class X may refer to a variable of class
X, but no other method of any other object may do so. Private
variables are as good as public variables are bad.
Also good are protected variables. They may be referenced by
methods of their own class as well as by classes that descend
from it.
Accessors Typically, variables are referenced by accessors--
functions whose duty is simply to return a value, as in the fol-
lowing code"
Accessors typically come in pairs. The complement to the
code above would set the value:
Accessors generically describe the types of routines shown
here; you may refer to them more specifically as getters and
putters, but that is poor English.
Accessors are a good idea in all code--even traditional proce-
dural programming.
At a fairly high level, object-oriented programming is a way
for programmers to be more productive. They can feel more
in control of their code because it is broken up into sturdy
9
chunks, and the opportunities for reuse--not fully realized
yet--are very attractive.
At a low level, object-oriented programming means the end of
statements and their statement cousins. In
traditional procedural programming, the employee example
used previously would probably have been written in this
fashion:
Or, if only two cases can occur, it could be written as follows"
Code with conditions (such as i f and swi t ch statements) is
very hard to debug. The number of possible execution paths
quickly becomes enormous. In object-oriented programming,
the conditions are normally moved outside the objects. A spe-
cific type of employee object is created and within its process-
ing (salaried or hourly) everything proceeds in a clear and
straightforward manner with very few branches.
The benefits of sequential processing are e n o r m o u s ~ p a r t i c u -
larly in debugging and maintaining code.
Accessors allow you to easily add all types of filters to data.
For example, if an accessor returns the coordinate of a point at
which to draw an interface element, the accessor can take into
account a scale factor for the view in which it is d r a w n and ad-
just the point accordingly.
Here are a few examples of how that could be done, following
on from the accessors discussed previously. Together they
give you an idea of some object-oriented design issues.
This is fairly straightforward, but it is quite specific. What if
your interface allows you not only to scale the view, but also
to relocate it within a larger context? You could create a Ge t -
to do this would surely alert you to the possibility that other
changes may come d o w n the road.
A more general w a y is to construct a new object that can en-
capsulate all possible adjustments. The new object could be
called something like CoordinateAdjuster; its instance vari-
ables would include a scale factor, an offset, and any other
possible modifiers. The accessor then becomes
A change to the imaging algorithms would entail only a mod-
ification to the CoordinateAdjuster object (addition or dele-
tion of an instance variable and accessors) and a possible
modification to the Ge t L o c a t i on code. No calls to Ge t L o c a -
t i on would have to change and anyone who uses it w o u l d
likely be shielded from the changes.
A final structure provides an even more sophisticated meth-
odology:
The method of the View object
might look something like this:
In this final version, you can see a number of object-oriented
p r o g r a m m i n g techniques and issues coming into play. The
most interesting one is the decision as to where to place vari-
ables and functionality. In the first case, the scale factor and
offset were simply passed in as parameters. With the creation
of the CoordinateAdjuster object, t h a t ~ a n d other~data
could be encapsulated in an object that could itself be shared.
This object can be passed around by other objects that have no
knowledge or interest in its internals.
Finally, you see the CoordinateAdjuster object being used as
a data member of the View object. Someone who is interested
in finding a point at which to draw something need not even
know if there is a CoordinateAdjuster involved: It is totally
the View's business.
The ultimate decisions on where to locate data and function-
ality often take much trial and error. Fortunately, with object-
oriented programming the revisions are usually fairly easy to
make.
When object-oriented programming began to become widely
used in the mid-1980s, a number of people went ballistic over
this hiding of data. They passed around detailed analyses of
the "wasted" processor cycles spent in getting to data through
method calls.
Suffice it to say that 50 years of experience with computers
shows that they get faster and cheaper~wasted cycles are of
less and less importance. On the other hand, programmers get
scarcer and more expensive. A technology that optimizes a
programmer's time at the expense of a computer's time is
right on the mark.
You can design an object-oriented programming language
whose "object-ness" disappears at run time. For example, the
initial C++ used a preprocessor that turned everything into C
for compilation; strictly speaking, no object-oriented lan-
guage constructs remained, although some object-oriented
structures were created in the process.
Two major run-time issues affect all object-oriented program-
ming projects to a greater or lesser extent: dynamism and
management of objects in memory.
Dynamism (which is discussed more fully in the chapters on
Objective-C and Java) refers to the general notion of allowing
objects to be assembled and connected at run time rather than
at compile time. The general concern is larger than an arcane
compiler issue: It involves the ad hoc combination of objects
over a network that may have been written in various lan-
guages.
Dynamism is a very important concept; with the advent of the
Internet as a pervasive connectivity tool, the ability to com-
bine objects over networks is becoming increasingly impor-
tant. Mac OS X and Cocoa specifically address these issues in
many ways, and much of Part III is devoted to these concerns.
Instances of objects are created from some big glob of memory
(not to be too technical about it). In this sense, they are very
different from the variables that are created on the stack in tra-
ditional methods. If you declare an integer i inside a block, its
memory is deallocated when you leave that block and the
compiler will not recognize references to it beyond that scope.
By their very nature, objects exist in another dimension than
the scopes of blocks and functions. While some small objects
are created on the stack in C++ (and automatically are deleted
when control passes out of their block), most objects need to
be kept around.
Two issues need to be addressed. The first is the decision of
how to create these objects. Most commonly, chunks of mem-
ory are allocated for object creation; as objects are created and
therefore use up memory, other chunks are created. Years of
experience with much object-oriented software (particularly
MacApp) showed that memory usage for objects is very dif-
ferent from memory usage for other purposes. Object-specific
memory managers have been developed and will continue to
be developed.
The flip side of the memory allocation issue is the problem of
knowing when to delete objects. Cocoa relies on a reference-
counting mechanism to automatically delete objects when it is
safe to do so. In all cases, for automatic deletion (garbage col-
lection) to work, the programmer must take a few modest
steps to enable the functionality.
Frameworks like MacApp and Cocoa are collections of objects
that are designed to work together. You use many of the ob-
jects directly; others are subclassed or used with various ex-
tensions such as delegates (Cocoa), or behaviors and adorners
(MacApp). Together, the framework objects, your subclasses
of them, and your totally customized objects allow you to eas-
ily create an object-oriented application.
This chapter has presented some of the high points of object-
oriented programming and noted some of the issues that
come into play as you start to use object-oriented tools. Mac
OS X is thoroughly object oriented, and it allows you to use its
framework with several languages.
The languages of Mac OS X~Objective-C, C++, and Java~are
described in the following chapters.
Java caught the imagination of the programming world in the mid-
1990s. It seemed to promise one of the long-sought objectives of ob-
ject-oriented programming~the ability to write objects that could
be used and reused in different contexts without having to recompile
and relink them. In fact, Java does do this to a large extent.
Java was designed originally as a language to use for embedded mi-
croprocessors in consumer appliances. Issues such as stability, reli-
ability, and compatibility with network communications were
paramount. On the World Wide Web, these issues turned out to be
very important, and the ability to write and compile Java applets
once and to deploy them via Web pages is very important.
65
Java can be used to create applets~small programs that can be dis-
tributed over the Web and embedded in HTML. It can also be used
as a traditional programming language. In Mac OS X, a Java Vir-
tual Machine is included as part of the overall architecture so that
applets can run. FUrthermore, you can use Java as a programming
language for Cocoa.
This chapter provides a high-level look at Java, emphasizing some of
its similarities to and differences from other object-oriented pro-
gramming languages. As with the other chapters in this section, it
is no substitute for a complete language reference. However, if you
are an experienced object-oriented programmer, you may well find
that the sample code from Apple is sufficient to get you going with
Java (or Objective-C or C++) as you start to experiment with Cocoa.
If you look at Java code, two things may strike you immedi-
ately:
1. Java allows Unicode characters.
2. Java looks a lot like C and C++.
Most programming languages limit the characters that their
compilers will process to standard ASCII characters. This
eliminates such useful symbols as ~ and ~ as well as all non-
Roman characters and a number of non-English characters.
Java accepts any Unicode character, which makes it possible
to write readable code in any language. (Unicode characters
are 16-bit characters; you can represent not only the standard
ASCII upper- and lowercase letters in Unicode, but also the
double-byte characters from non-Roman alphabets.)
Java looks like C and C++. However, there is one critically im-
portant difference: Java is not built on top of C. Both C++ and
Objective-C were designed to expand, enhance, and (in the
case of C++) improve C. They started with the assumption
that they would do not violence to the original language. C
code should compile without error in a C++ or Objective-C
compiler.
Java, on the other hand, is not built on top of C and is free to
reimplement C constructs. For example, C defines a basic type
called float to be a floating point number. Both Objective-C
and C++ therefore recognize the float type.
In Java, float is defined as a primitive type. In addition, how-
ever, Float is a class, a wrapper for the primitive type, float.
(This architecture applies also to other primitive and refer-
ence types such as boolean/Boolean, long/Long, and so
forth.)
This line of code has identical meanings in C, Objective-C, and
C++"
However, in Java, you can also write
Its meaning is similar, and you can write it and use r te
more or less as you w o u l d in the other languages, but by be-
ing declared as a reference type (Float) rather than a primitive
type (float) r r e will be an object in Java.
As you will see in Chapter 5, which covers Objective-C, class-
es in that language are themselves objects, and you can use
class methods and class variables as well as instance methods
and variables. Class objects are commonly capitalized, while
their instances are not. Thus in Objective-C
calls the Triangle class's a 11 o c method, while
calls a specific triangle instance's draw method.
Java uses a C++-like syntax in which classes can have static
fields and methods; those fields and methods belong to the
class, not to particular instances.
In Objective-C, classes are members of the Class class, and
they inherit some utility methods from it. Java approaches the
issue somewhat differently.
In Java, all objects are descendants of the Object class, and
they therefore inherit the utility methods from it. Object has
12 methods; therefore all Java objects have at least these 12
methods--either by inheritance or through overrides. Be-
cause every reference type is a descendant of Object, every
Boolean, every array, every String, and every Float can do any
of the things listed in Table 4-1.
Method Use
constructor
provides a copy of itself with all fields set
to the same values as in the original
returns true if another object is the same as
this one (i.e., refers to the same object in
memory)
does nothing; similar to a C++ destructor;
designed to be overridden in subclasses
returns the run-time class of an object
(run-time classes are described later in this
chapter)
returns an integer value that uniquely
identifies this object at run time; different
values may be returned during different
executions
wakes up a thread waiting on this object's
monitor
wakes up all threads waiting on this ob-
ject's monitor
returns a textual representation of this ob-
ject; it is meaningful (to people) and con-
cise but usually is not the entire object's
data
waits for a thread to notify it of a change
waits with a timeout in milliseconds
waits with a timeout in milliseconds plus
nanoseconds
A glance at the methods will show several important aspects
of Java:
Java is designed for a multithreaded environment
( n o t i f y , n o t i f y a l l , and w a i t methods).
Java defines a run-time object (Class) that interacts
with the descendants of Object that you describe in
your code.
The h a s h C o d e method demonstrates Java's imple-
mentation of a mechanism for locating and identifying
objects on the fly at run time.
The f i n a 1 i z e method is called when an object is be-
ing automatically destroyed by Java's garbage collec-
tion mechanism. You don't have to do anything to
have automatic memory management with Java.
The actual O~ect API shows several language features that
distinguish Java from other languages. Here is the API:
These are some of the syntactical elements that distinguish
Java from other languages"
N a m e s in Java can be qualified to make them unique,
as in java.lang.Object. You can create your o w n name
space; the convention is to reverse your Internet do-
main to provide a unique identifier. Thus, Apple's In-
ternet address is apple.com; a unique Java identifier
for Apple Java objects is com.apple. (Because the Inter-
net domains are unique, the reversed-order identifiers
are also unique.)
The c 1 one and g e t c 1 a s s methods return objects. In
C++, they w o u l d return pointers to objects--Object*
and Class*. Because everything in Java is an object, it
is unnecessary to distinguish between references and
objects. As there are no pointers in Java, that distinc-
tion w o u l d be irrelevant.
Methods can be m a r k e d as final, which means that
subclasses cannot override them. This is in contrast to
the approach in C++, where methods are m a r k e d as
virtual to indicate that where a like-named method ex-
ists for a subclass, that m e t h o d should be used instead.
C++ asks you to specify w h e n a m e t h o d will be over-
ridden; Java asks you to specify w h e n it c a n n o t be
overridden. Classes and fields can also be m a r k e d as
final.
In the case of Object, only c 1 on e, e qua 1 s, f i na 1 i z e,
h a s h C o d e , and t o S t r i n g can be overridden. As they
all obviously need to use the fields of a specific descen-
dant of Object, this makes sense. You cannot override
the t h r e a d - m a n a g e m e n t and run-time class manage-
ment methods.
Organizing the parts of an object-oriented system is always a
challenge. C++ provides for organization primarily through
the use of inheritance (including multiple inheritance). Objec-
tive-C supports not only inheritance, but also the concept of
protocols--sets of methods that as a unit can be adopted by an
object.
Java addresses the issue in a somewhat similar manner to Ob-
jective-C. Any class can be a descendant of any other class. In
Java terms, a subclass extends its superclass, as in
This Boolean class wraps the primitive Boolean value that cor-
responds to the Boolean type in C. It uses fully qualified
names for itself and its superclass (java.lang.Object); by being
declared as final, the class cannot be overridden.
You can also declare an interface that looks like a class decla-
ration, complete with methods and fields. A specific class can
extend a given superclass and may implement any number of
interfaces in a manner somewhat similar to Objective-C's
adoption of protocols.
You can query the Class object at run time to find what (if any)
interfaces it implements.
You can assemble classes into a package in a single source file
and import the package as a whole. You identify the package
with a fully qualified name using the convention cited previ-
ously of starting with your reversed Internet domain name (as
in corn.apple).
You can then import a package into any other Java file. Names
are unique within packages a n d ~ i f you are using the reverse
Internet naming convention--package identifiers will be
unique. You can refer to items within a package either by us-
ing fully qualified names or by having imported the package.
From the start of object-oriented programming, there has
been uncertainty over what features should be part of the lan-
guages and what should be part of a framework. C++ is very
pure in this sense--it has no framework-type constructs (such
as a common object from which all others descend).
Objective-C has some framework-type syntax; when used
with Cocoa, it, of course, is tightly bound to that framework.
For example, NSObject is the common ancestor of most Cocoa
objects and has many common utility functions that Cocoa
objects can use.
In Java, the use of a common ancestor (Object) in the language
itself means that some of the framework-type functionality
moves into the language. This includes object inspection at
run time (what type of object is this, does this object support
X, etc.) as well as extensive exception handling.
Java uses the t r y / c a t c h / f i n a l l y mechanism that is famil-
iar to most programmers today. Method declarations explicit-
ly specify the exceptions that may be thrown with a throws
clause:
Exceptions themselves are objects. Using the principle of
polymorphism, you may actually throw a descendant of the
exception type specified in your declaration.
Cocoa is written in Objective-C. A mechanism called the Java
bridge exists to let you call Objective-C code from Java (and
vice versa). The bridge is so effective that you may not really
notice it at all: You can write your Cocoa code, calling appar-
ently Java classes and methods, without being aware of the
bridge in most cases.
There are two situations in which you do need to be aware of
the bridge. In the first, you should realize that, yes, there is a
slight effect on performance when using the Java bridge. This
does not mean that Cocoa applications written in Java are
slow: Most applications on personal computers spend most of
their time waiting for user input. Even the fastest typist can-
not keep up with today's processors. If you are writing an ex-
traordinarily demanding application, you may need to
consider this. For most people, that is not the case.
The second occasion when you need to worry about the Java
bridge is when you need to call a Cocoa framework method
or use a Cocoa class and you do not have documentation for
it in Java. Most of the Cocoa documentation is provided both
in Java and Objective-C, but there are some lacunae.
In Project Builder, the Frameworks section of the project
structure pane lets you examine the header files of your
frameworks. These are in Objective-C (the file names end in
.h). If you are writing Java, you can often guess at the Java
syntax, but you need a definitive way to find out what the ac-
tual Java calling conventions and names are. JavaBrowser lets
you do this.
Located in the Applications folder of the Developer folder
(not in the standard Applications folder), JavaBrowser lets
you browse the structure of any Java classes. To get to Cocoa,
navigate through the browser hierarchy at the top as follows:
1. corn
2. apple
3. cocoa
0 application or foundation (the AppKit framework is
under application; the Foundation framework is un-
der foundation)
The JavaBrowser window is shown in Figure 4-1. The three
buttons at the bottom let you switch among views of class de-
scriptions, source code (if available), and documentation.
The documentation view is shown in Figure 4-2. Next to the
headers, buttons allow you to copy the text to the clipboard,
from whence you can paste it into your application.
Most Objective-C classes are wrapped in this way, and you
can access them using the syntax shown in JavaBrowser.
Some--particularly basic classes in the Foundation frame-
work--are morphed into standard Java classes (arrays, for ex-
ample, are handled in this way). The functionality that you
need is provided for you, but you use the underlying Java
class, not the underlying Objective-C class.
There are a very few classes and methods that are not accessi-
ble from Java. Rarely do you need to use them in day-to-day
Cocoa programming.
There is much more to the Java bridge, but this is probably all
that you need to know for most purposes. The complete doc-
umentation for the Java bridge is available on Apple's Web
site both as a PDF file and in HTML. 1
This chapter summarized the high points of Java~particular-
ly as they differ from C++ or Objective-C. The principles of
Java are those of object-oriented programming: inheritance,
polymorphism, and data hiding/encapsulation.
Java specializes in providing a particularly robust run-time
environment and in providing a well-structured way of com-
bining objects. Java's packages, interface/implementation
structure, and ability to specify that methods, fields, or classes
are not overridable (with the final keyword) provide a sturdy
foundation.
Furthermore, Java's choice of not implementing multiple in-
heritance (although providing some of its features through in-
terfaces) increases the manageability and maintainability of
Java code. While multiple inheritance is one of the topics that
can set off religious wars in the programming community, it
is not one of the features that makes for easily maintained
code.
Java is very close to Objective-C in its structure and in the de-
gree to which it implements some important run-time fea-
tures. By contrast, C++ is very sparse in making any
assumptions about what happens at run time. Its power is fo-
cused on the compile-time language and its constructs.
1. http: //www.devworld.apple.com/techpubs/macosx/Cocoa/
ProgrammingTopics/JavaBridge/JavaBridge.html).
This Page Intentionally Left Blank
Cocoa is one of the principal programming tools for Mac OS X (the
other is Carbon). It was developed in Objective-C; you can use Ob-
jective-C or Java to reference its application programming interface
(API~the routines that do the work). Additionally, you can use
C++ in your code to do application-specific processing using Objec-
tive C++. Integrating legacy C++ code with Cocoa is not a problem.
Just as with natural languages, choices of programming languages
quickly spark passionate battles. In fact, while there are substantive
differences among the three languages of Mac OS X, they have much
more in common with one another than they have with traditional
procedural languages. You would be quite justified in worrying
what all the fuss is about, except for the likelihood that even express-
79
ing such a thought might subject you to suspicion on the part of the
language purists.
This chapter starts with a brief summary of how the object-oriented
programming languages developed and diverged. It continues with
some highlights of Objective-C:
9 Dynamism
9 Class and instance objects
9 Protocols
Note that these language chapters are highly interrelated, as they
contrast the differences among the languages. For example, this
chapter discusses Objective-C and C++ almost equally as it demon-
strates the differences in the languages from the Objective-C side.
The corresponding C++ chapter focuses at length on Objective-C
and Java as it draws its own distinctions and comparisons.
The origins of object-oriented programming in the 1970s lie
with Smalltalk and Lisp: development environments that
were used for experimentation, development, and, later, pro-
duction. The distinction between the language and the devel-
opment environment was not clear (nor was it intended to
be). In recent years, the Dylan language has rethought and ex-
tended these concepts; its popularity among developers (and
lack of popularity among managers and end users) in many
ways has repeated the experiences of Smalltalk and Lisp.
The initial model of object-oriented programming was of ob-
jects (often based on real-world models) sending messages to
one another. Thus, documents sent draw messages to rectan-
gles, employees sent timecard messages to payroll objects, etc.
When an object receives a message, it acts on it~typically by
invoking a method or function of its own. C++ programmers
usually emphasize the method or function; Smalltalk and
Lisp programmers usually emphasize the message. Because
the message commonly invokes a method of the same name,
there is not a great deal of practical difference between talking
about the draw message and the draw method. (There is a dif-
ference, but it is subtle.)
The evolution of object-oriented programming has moved in
two directions:
0 The objects of modern object-oriented programming
are often not analogues of physical objects; they may
be very esoteric and abstract objects.
D The combined language/development environment
of Smalltalk, Lisp, and Dylan has evolved into more or
less separate worlds of languages (Objective-C, C++,
and Java) and development/run-time environments
(Cocoa, Java Virtual Machine, etc.).
The evolution of object-oriented languages has followed two
main paths, both based on the C programming language. Ob-
jective-C added Smalltalk-like object and messaging syntax
onto C; the result was intended to be as C-like as possible with
the object-orientedness retaining its distinctive object/mes-
saging roots. The other path~which led to C++ and then in a
different way to Java~approached the problem as one of en-
hancing and improving C and incorporating object-oriented-
ness into the language as if it had always been there.
As a result, Objective-C on the page looks very different from
C and from C++. It is designed to emphasize and separate the
distinctions. On the other hand, C++ looks very much like C
because its object-orientedness has been deliberately de-
signed to look C-ish.
There are advantages and disadvantages to each approach.
As usual in the cases of both natural and computer languages,
saying something so eminently reasonable and true will likely
get your head handed to you on a platter.
Perhaps the most important feature of Objective-C as com-
pared to C++ is its dynamism. Dynamic typing, binding, and
loading/linking replace or expand features of a C++ compiler
and are performed at run time.
In C++, every object you refer to in your program is typed.
You can use any of its methods--either methods declared in
the object itself or methods in any of its ancestors. For exam-
ple, the following syntax is legal in C++ and would allow you
to ask a view object to return the shape at a given mouse loca-
tion:
If the class of theView contains the following method
that code will work.
In MacApp, for many years most objects were descendants of
TObject (they aren't now). Thus, the following method decla-
ration would not allow you to write the line of code above:
a TObject as a TShape (although you can do the reverse). To
avoid a compile-time error, you would need to rewrite the
line of code as
way of knowing that the TObject return value of Oe t Shape-
UnderMouse could in fact be a TShape and that the code
would therefore succeed.
This is not a matter of idle curiosity, because if you have dy-
namic typing, you can then have dynamic binding~which is
the really big deal.
In the previous example, you could continue and write code
such as the following to highlight the shape if it had previous-
ly been unhighlighted, or vice versa:
value indicating whether the shape is highlighted; the method
theShape->SetHighlight sets the highlight value. This
code snippet sets the shape highlight to the opposite of its cur-
rent value.
This code will work for objects of type TShape or objects that
are descendants of TShape (as TCircle, TRectangle, TTriangle,
etc., might be). It will compile as long as TShape contains the
methods
If all of the objects in your application (or framework) are de-
scended from a common ancestor such as TObject was for
much of MacApp's life, you could not write the following:
To avoid a compile error, t h e S h a p e must be an instance of
type TShape or one of its descendants. In the class hierarchy
Dynamic binding moves the checking of whether G e t H i g h -
the compiler to the run-time environment. Thus, in Objective-
C, the preceding code snippet (in which t h e S h a p e is given
no further definition than being of type TObject) would com-
pile. It would generate a run-time (not compile-time) error if
the actual object t h e S h a p e as returned at run time from Ge t -
ShapeUnderMouse did not support G e t H i g h l i g h t and
Note that in Objective-C the common type for generic objects
is id. Thus, the code snippet would read as follows:
Dynamic typing has many design consequences for the devel-
opment of frameworks and applications. In statically typed
languages such as C++, there is a constant struggle to find the
appropriate places for methods. Because a common ancestral
class must contain the methods that all descendants need to
use (such as S e t H i g h l i g h t ) , the temptation is either to load
up an ancestral class with many methods--some of which
will not apply to descendants--or to use multiple inheritance
so as to provide several ancestors for each object, with each
ancestor providing the set of methods appropriate.
In the latter case, you might have an ancestor object called
HighlightableObject that you could mix into appropriate
shape objects; other possible mix-in objects would be Dragga-
bleObject, EditableObject, etc. However you do it, though, at
compile time your theShape object must have a G e t H i g h -
method.
The C++ fragile base class problem just exacerbates this. The
fragile base class problem is illustrated by the following sce-
nario. If in the course of developing an application you dis-
cover the need to add a method to an ancestor of a class, all
classes that descend from that class need to be recompiled.
Thus, you can add D r a w R e s i z e H a n d l e s to a TCircle object
with little difficulty; if your development process leads you to
believe that you should really have a D r a w R e s i z e H a n d l e s
method at the TShape level, TCircle and TRectangle (both of
which may need it) will need to be recompiled--as well as
TTriangle (which, for some reason, might not strictly need
D r a w R e s i z e H a n d l e s but nevertheless will need to be re-
compiled due to the changes in TShape).
With dynamic binding, you can avoid bloated superclasses
and minimize recompilation due to the fragile base class
problem.
The third aspect of dynamism is the ability to load and link
code dynamically as needed. This capability is available to
greater or lesser degrees even with languages such as C++;
when combined with dynamic binding, however, the ability
to assemble code on the fly presents many opportunities.
In languages such as Objective-C and SOM (the System Object
Model), classes themselves can be run-time objects. As with
the other issues discussed in this chapter, this can be a matter
for esoteric speculation and argument; it also has practical im-
plications.
In C++, you create a new instance with the new function:
The instance's constructor method is called automatically.
In Objective-C, if you have declared a Triangle object, you cre-
ate a new instance by calling a method of the class object
which creates a new instance.
By convention, the a l 1 o c method creates a new object. Note
the difference: The C++ example uses a function (new) that is
not an object-oriented construct; the Objective-C example
uses an object-oriented construct in the form of the class object
(Triangle).
Each declared class has a single class object that is referenced
by the class name (Triangle here). You define methods for
each class as being available either to the class object (such as
a l 1 or or to the instance objects. The code
would fail, because a l 1 oc is a class method (available only to
Triangle and not to any specific instances such as myTrian-
gle).
The distinction between class and instance methods is shown
in their declarations. Class methods are preceded by +, and in-
stance methods are preceded b y - .
Here is a class declaration:
Here is an instance declaration:
Rather than relying on a constructor, you call an initialization
routine (which by convention starts with i n i t).
Thus, the code to allocate and initialize a triangle could be
written as follows:
As you can surmise, the result of the a 11 o c method is an in-
stance of Triangle on which the i n i t method is called; the re-
sult is stored in myTriangle.
Class objects are of class Class; instances are objects of their
given class.
Class objects can also be used for purposes other than simply
as factories to create instances of themselves. If you have writ-
ten C++ code, you may have experienced the joys of getting
yourself w r a p p e d up in Run-time Type Identification (RTTI),
in which you need to find out whether an object that you hap-
pen to have is an instance (or descendant of) a certain class.
This often happens w h e n you are maneuvering around the
limitations of static typing and b i n d i n g ~ b e f o r e coercing a de-
scendant of TShape to a TCircle, for instance, it's a good idea
to confirm that it is a TCircle.
A class object can return its c l a s s ~ n o t its class name (which
you can derive from the c l a s s ) ~ b u t a return value of type
Class.
C++ relies on class hierarchies to create objects~a class's
methods are the ones it declares as well as those of its ances-
tors. With multiple inheritance, you can mix in a number of
classes, each of which is targeted to specific functionality.
Objective-C does not support multiple inheritance, but it does
support a multidimensional structure to create objects. As in
C++, a class's methods include its own as well as those of its
ancestors. In addition, you can declare protocols~which are
collections of m e t h o d s ~ t h a t can mix into classes.
A protocol could consist of mouse management methods (you
could have a protocol to implement the hypothetical Dragga-
bleObiect mix-in class mentioned previously). Classes are said
to adopt protocols; they conform to protocols if they either
adopt them or are descendants of classes that adopt them.
Unlike mix-in classes in C++, protocols consist only of meth-
ods (not instance variables). Furthermore, protocols merely
define the methods that the class adopting the protocol must
implement. The protocol itself contains no implementations
but is applicable only to the interface.
In declarations, a generic id can be qualified with a protocol.
Thus id<NSCoder> refers to any object that adopts the
NSCoder protocol.
A category is an extension to a class, somewhat similar to a
subclass, but only to a certain extent. Categories are used to
implement delegates and notifications in Cocoa.
In common use, a category (such as NSToolbarDelegate) ex-
tends another class~such as NSObject in this case:
Another category also extends NSObject~NSToolbarNotifi-
cations:
Although they extend NSObject (that is, any object in Objec-
tive-C), these interfaces are found in the NSToolbar and NS-
Notification interfaces (usually at the bottom of those files).
You implement your code for them in your implementations
of objects to which they will be attached as delegate or notifi-
cation. In Java, you implement notifications and delegates at
the bottom of the class files that will use them.
The strict compile-time type checking that C++ provides
helps to make certain that you do not wind up calling a non-
existent method. In Objective-C, you have a choice: You can
do that work yourself at run time or you can use static typing
to have the compiler do the work for you.
As noted previously, an Objective-C object responds to a mes-
sage that selects a method or function to invoke. Accordingly,
the message may be called a selector--as it is in the following
code snippet. All objects that descend from NSObject (and
hence most of the objects you will be working with) have a
r e s p o n d s T o S e l e c t o r method to which you pass a selector
that consists of the method you want to check:
You can also use variables of type SEL to store references to
selectors that you may use frequently:
Checking is as natural to Objective-C
programmers as checking for NULL objects is to C++ pro-
grammers.
Cocoa also provides a method of NSObject that you can over-
ride
In Objective-C, messages are sent to receivers, sometimes
with parameters. For example, if you have a view object that
responds to the G e t S h a p e U n d e r M o u s e message with a point
parameter that describes the mouse position, you can write it
as
All Objective-C messages are embedded in square brackets.
If there is more than one parameter, you may name the subse-
quent
The first parameter is never named.
The result is returned and can be assigned to a variable. In this
case, it is logical that an object be returned. All objects can be
referred to as type id, so you could write
However, using static typing (that is, a specific type rather
than the generic id) will cause the compiler to check that the
call is legal. Many people would prefer the following line of
code:
Objective-C++ is the set of Apple's extensions to the compiler
in Mac OS X developer tools that lets you mix and match Ob-
jective-C and C++. No longer do you have to make a total
commitment to one language or the other.
The most powerful use of Objective-C++ is in its ability to let
you merge legacy code (often in C++) with new, Objective-C
code. In such a case, you will find that your code generally
stays on one side of the Objective-C/C++ fence or the other.
An example of the use of Objective-C and C++ together is
found at the end of Chapter 6, which deals with C++.
This chapter summarized the high points of Objective-C for
object-oriented programmers who are familiar with other lan-
guages. The rest of the syntax is quite comparable~interface
and implementation files are used just as they are in other lan-
guages. Directives to the Objective-C compiler start with @,
which is a change from other languages, but that shouldn't
stump you.
What matters most about Objective-C is its dynamic nature,
which makes much of the Cocoa frameworks possible. It also
eliminates the need for some of the more complex C++ struc-
tures (in particular, multiple inheritance).
Protocols, for example, allow the creation of complex objects
along two dimensions~one dimension of inheritance and an-
other dimension of common functionality.
Objective-C is very much a product of the object-oriented
world of the 1980s. It takes the then most popular program-
ming language (C) and adds object-orientedness to it without
touching the basic C syntax. It incorporates the very concrete
notions of objects as message processors that were prevalent
in Smalltalk, Lisp, and other early object-oriented systems.
Do not make the mistake of thinking that Objective-C is dated
or old-fashioned. Its roots are different from those of Java and
C++ but all of these languages evolved over time; the fact that
they evolved in different environments accounts for some of
their differences. If there were a clear developmental struc-
ture of A being supplanted by B, which in turn was supplant-
ed by C, there would be no question that C is the preferred
language. That is not the case, and there are reasons to use
each of these languages today.
As people have used object-oriented programming tech-
niques, their approach to architecture has changed. Objects
have gotten smaller and smaller. In Java, the most recent object-
oriented programming language, everything is an object~as
you saw in Chapter 4.
This Page Intentionally Left Blank
C++ is the other major language that you can use with Mac OS X.
Perhaps the most widely used object-oriented programming lan-
guage today, C++ has many partisans and experts; in addition, a
great deal of existing code (tomorrow's legacy code) is written or is
being written in C++.
You can use C++ with Mac OS X, and you are encouraged to do so.
The mingling of C++ with dynamic object-oriented languages (Ob-
jective-C and Java) is no problem within the basic functional sec-
tions of your code. For the interface, you should use Interface
Builder, which provides a consistent interface and a modern graph-
ically oriented interface building environment. C++ has a limited
role to play in that area.
95
This may worry you: What about all that existing code? What about
your expertise ? Have no fear~most of that code is reusable or easily
modified, and your expertise is primarily at a higher level than lan-
guage syntax. Your favorite C++ language tools are available with
Mac OS X's dynamic languages. They may go by different names,
and fierce partisans of one language or another may fight to the bit-
ter end saying that the language structures aren't parallel, but from
the practical point of view of the professional programmer, the dif-
ferences are not great. What true differences there are all revolve
around the issue of dynamism---dynamic binding, loading, and typ-
ing~as well as around multiple inheritance.
The tight integration of C++ code with Cocoa is accomplished with
Objective-C++, a tool that is part of the second wave of Mac OS X
development tools released in version 10.1. C++ on Mac OS X is
used extensively in legacy applications and in the MacApp and
PowerPlant frameworks that are used to build applications that run
in the Carbon environment.
This chapter covers a few of the hot issues regarding C++ and Mac
OSX.
"C with Classes" began its life at Bell Labs in 1979. It was de-
signed from the beginning to be a production language~one
that would be usable in real-world everyday projects. In this
respect it differed from Smalltalk and Lisp, which were exper-
imental languages. Smalltalk and Lisp (as well as Simula) con-
vinced a number of computer scientists that there was indeed
a practical benefit to the use of object-oriented programming.
What was necessary was a way to bring it into the world
where production programming was being done.
When C with Classes became C++ in 1983, the computing
world had changed dramatically from what it had been only a
few years earlier when C with Classes was born. The personal
computer was well on its way to becoming the widespread
phenomenon it is today. Programmers and users alike were
turning from mainframes to personal computers because of
the ability to do their computer work themselves without the
mediation of large professional staffs.
In the early 1980s, personal computers were far from the pow-
erful devices that exist today. The first Macintosh (1984)
boasted 64K of memory. More than fifteen years later, a thou-
sandfold increase in memory to 64MB is not uncommon;
many computers ship with 256MB as s t a n d a r d ~ a 4000-fold
increase.
In an earlier era, computer resources~memory, processor,
and disk storage~were husbanded carefully. The first com-
pilers on personal computers were designed to run in very
small memory partitions at the expense of constant diskette
swapping as memory structures were swapped to and from
disk.
It is therefore not surprising that when a new language was
developed it was designed to respond to the needs of the pro-
gramming community. The single most significant design de-
cision of C++ was the choice to move all possible decisions
from run time into the compiler. It might take longer for the
program to compile, but the finished code would run as
quickly as possible.
This was a change from the designs of the predecessors of
C++. Lisp and Smalltalk were dynamic languages~a lot hap-
pened at run time. They had reputations as being very slow
(which they were), and object-oriented programming had a
big hurdle to overcome because many people believed that it
automatically meant at best sluggish performance of the final
product.
The decision to make typing static (rather than dynamic) and
not to support run-time binding was far from a mistake. In
fact, you can argue quite convincingly that by making object-
oriented programming feasible in the real world, C++ was
largely responsible for moving it from computer labs to the
workplace.
Today, processors are much faster, memory is plentiful, and
disk space is cheap. Dynamic languages such as Objective-C
and Java are not disadvantaged by their dynamism, although
you can still hear legitimate concerns about the performance
of Java (this is improving by the day--it is unlikely to remain
a serious issue). If you go back and read some of the books
about the evolution of C++, you will find emphasis on the
need to keep the run-time performance of C++ programs as
high as possible as well as on the need to make the code as
portable as possible. The choices with regard to dynamism
(specifically, the decision not to use it) are related to these con-
cerns far more than to abstract designs.
C++ is not a dynamic language, and that's that. It was the
right language at the right time, and every object-oriented
programmer today owes a tremendous debt to the C++ de-
signers who made the choices that made the language and the
technology usable.
By forcing the compiler to do as much work as possible, the
run-time code is kept very efficient. The flip side is that in C++
design decisions and implementation choices must be made
much earlier in the development process than is possible with
dynamic languages.
Two consequences of compile-time typing are discussed in
this section: the use of small, stack-based objects, and the frag-
ile base class problem.
No matter how much the compiler and operating system try
to minimize the impact, object-oriented programming and its
attendant data structures do exert a cost at run time. Program-
mers have known this from the start; particularly in early
days, the use of objects was quite limited. Because of the over-
head involved in constructing and accessing objects, the ob-
jects tended to be fairly large structures.
Over time, it became feasible to use small objects~sometimes
very small objects--in programs. Because much of the object
management is done by the compiler, there is little run-time
cost associated with these small objects. Furthermore, some
frameworks have their own memory allocation routines that
optimize the allocation and deallocation of these small struc-
tures; the OS memory allocation routines were often
optimized for relatively large objects and data structures.
Small objects often have very brief lives. In MacApp, for ex-
ample, you will find objects that wrap platform-specific struc-
tures such as points and rectangles. These objects are used
precisely as the flat structures would have been used. That is,
they are declared on the stack at the beginning of a function
and are implicitly destroyed when control passes out of the
function, as shown in this code snippet:
ooo
On exit from the function, neither i nor aRect is available for
use. The C++ compiler has taken care of preparing the stack
to be cut back; it has also taken care to make certain that any
constructors and destructors for aRect are automatically
called.
In fact, many programmers use this feature to release memory
structures automatically. If you create a small stack-based ob-
ject that wraps a standard toolbox call, you can implement a
single m e t h o d ~ i t s destructor~and be guaranteed that it will
be called automatically as necessary to deallocate auxiliary
memory structures and other resources.
The referencing of methods within an object is done by the use
of a virtual dispatch table for each class~a vtable~that is
built at compile time by the compiler. These vtables make
run-time dispatching extraordinarily efficient.
In Objective-C, there are no vtables. The dispatching is done
at run time by highly optimized code that checks at that spe-
cific moment to find the method to call. With today's proces-
sors, the performance hit is rarely noticeable. However,
because it is there and can be noticeable with a multitude of
small objects, Cocoa rarely uses small objects such as the
CRect object in the preceding code snippet. (NSRect in Cocoa
is a struct, not a class.)
The fragile base class problem is perhaps the most serious issue
plaguing C++. Because all of the mapping of objects is done at
compile time, every class's header structure must be known
then. A change to any class's header requires recompilation of
all of the classes that descend from it. This has caused severe
problems as people have tried to reuse objects.
A number of attempts have been made to work around the
fragile base class problem (including the System Object Mod-
el~SOM), but it remains a fundamental issue in dealing with
C++.
Recent additions to C++ provide the ability for objects to query
themselves and others about the classes to which they belong.
This feature (Run-Time Type Identification~RTTI) is stan-
dard in Objective-C but was a long time coming to C++. The
reasons it took so long were that not everyone was convinced
it was a good idea and, more importantly, it required building
and maintaining a run-time set of information about objects
that C++ had never had to keep before.
Related to RTTI is native exception handling. The standard
model for handling exceptions is shared by most contempo-
rary programming languages~declare a try block in which
you do the work, declare a failure block to which control is
transferred if something fails, and finally declare a comple-
tion block that is executed if things work properly.
C++ supports multiple inheritance; Objective-C and Java do
not. If you want to start a barroom brawl or language war,
bring up this point. People have very strong feelings about it.
In fact, to hear some people, multiple inheritance is the very
essence of C++.
Multiple inheritance appeared in C++ in Release 2 (June
1989). It was not part of the initial design for C with Classes.
So much for the "very essence of C++" argument!
Multiple inheritance is very useful and valuable; it is widely
used in frameworks such as MacApp, and it clarifies the pro-
gram structure. In its simplest form, multiple inheritance
means that an object can have two superclasses. In his book on
the development of C++, 1 Bjarne Stroustrup, the designer of
C++, presents three cases in which multiple inheritance can be
useful:
0 You can combine two completely separate objects into
a third.
1. The Design and Evolution of C++, Bjarne Stroustrup. Addison-Wesley,
1994, p. 271.
0 You can combine related objects. For example, Strous-
trup presents an abstract stream class, abstract input-
and output-stream descendants, and finally a file
stream class that merges the input- and output-stream
interfaces.
0 You can combine an interface and implementation
class to produce a fully configured object.
All of these are valid cases. The first can save recoding and re-
designing a new hybrid class; the second makes for more eas-
ily maintained code; the third may help you reuse utility
objects in a customized solution.
In practice, another aspect of multiple inheritance has become
obvious: Rarely do two objects of equal size and importance
become joined in the bonds of multiple inheritance (an excep-
tion is the structure of the symmetric input- and output-
stream objects in the second case cited). If you look at code
that uses multiple inheritance, there is usually a primary ob-
ject that mixes in some additional classes of relatively small,
focused functionality; these classes are called mix-in classes.
It is not surprising that the mix-in class structure should be so
popular. It provides the advantages of multiple inheritance,
while avoiding the programming headache of managing an
object that truly has two equal parent objects. It is much easier
to live in the mix-in world with a primary object and the sub-
sidiary, targeted mix-ins.
This usage of multiple inheritance is very important when
comparing C++ and its multiple inheritance to the single in-
heritance structures of Java and Objective-C. The functional-
ity of the mix-in flavor of multiple inheritance is provided
through delegation and, to a lesser extent, through the use of
protocols. These are no substitute for the Grand Scheme of
Multiple Inheritance, but they are a very satisfactory substi-
tute for the reality of the use of mix-in multiple inheritance.
In the nitty-gritty world of programming, multiple inherit-
ance means that you can call three kinds of methods from a
class that you create:
Q You can call methods that you declare and implement
in that class.
0 You can call methods from the first superclass of your
class.
0 You can call methods from the second (or nth) super-
class of your class.
The implementation of multiple inheritance must make this
possible. Object-oriented programming languages all provide
for the ability to call methods from your class and from a su-
perclass. It's calling a method from the second (or nth) super-
class that makes for multiple inheritance~and the problems.
An early attempt at imple-
menting multiple inheritance used the concept of delegation.
In your class's declaration, you could declare a delegate class.
If you called a method that was not in your class and not in
your superclass, the delegate class was given an opportunity
to perform the command.
This language-level implementation of delegation caused
problems. They were chiefly implementation problems for
programmers~the relationship between delegate and prima-
ry class was close but not close enough. For example, in the
multiple inheritance design as implemented today, you can
override methods from any of your superclasses. In the dele-
gation structure, you could override methods in your single
superclass, but not methods from either the superclass or the
delegate.
Another aspect of this problem was that while your class
knew about the delegate, the delegate had no reference back
to your class (unless you implemented one specifically). For
these reasons, language-level delegation in C++ was dropped
in favor of multiple inheritance.
used throughout Cocoa, and as implemented there
these problems do not occur (at least not nearly to the extent
they did in the early C++ experiments). Two types of delega-
tion are used:
1. You can declare a specific delegate variable for a class.
Your class will send certain messages to that delegate
for processing.
2. You can use the forwarding mechanism that is based
on overriding the NSObject
C++ world would get a chance). Your f o r w a r d I n v o -
ca t i on method receives all of the information about
the method being called and can attempt to forward
the message to any other object that can process it.
This structure provides much of the functionality of multiple
inheritance in C++. It also makes several points even clearer
than they are in C++:
There are clearly a primary object and subsidiary ob-
jects in the single superclass and possibly many dele-
gates. This conforms to the way in which most
programmers think.
You can control the calling of methods beyond your
own class and your superclass. Whether you use dele-
gation or forwarding, it is up to you to pass on the
message.
You can control which other object gets the message.
This control eliminates an area of ambiguity in C++
multiple inheritance, where there are many super-
classes with possibly conflicting names. The way
around this problem in C++ is to call a specific super-
class's method, qualifying it with that superclass's
name.
Because you manually establish the link to other class-
es (either dynamically with f o r w a r d I n v o c a t i o n or
by establishing a delegate), you can create whatever
context-specific links forward and backward that you
need.
Multiple inheritance is something people feel very strongly
about. In practice, you can accomplish what you need to do ei-
ther with C++ or with the Java and Objective-C structures.
There are pros and cons of both approaches. As you may
imagine, the Java and Objective-C architecture lends itself to
dynamic processing much more so than the static structure of
C++. (Of course as noted previously, dynamic processing
may push error checking from the compile phase to the exe-
cute phase and from programmer to user.)
Because the world of Cocoa is so bound up with dynamism,
the static structure of C++ poses certain problems with inte-
grating the dynamic objects of the Cocoa frameworks. Specif-
ically, you can't subclass the framework classes in C++, nor
can you (easily) call their methods.
Before you decide that this is a disaster, consider the implica-
tions. Most importantly, your C++ (or C) code can be used
within Cocoa applications. Any existing code that performs
application-specific functions can run quite happily in this
world. The code that will have problems is existing C++ code
that deals with the program interface.
If you are converting code to Mac OS X, that is far less of a
problem than it might appear. Throwing out pages and pages
of legacy C++ code in favor of using the standard interface is
a benefit for everyone. You have less code to maintain and
test, and you are guaranteed a consistent and conforming Mac
OS X interface. Throwing out legacy C++ interface code doesn't
mean rewriting it--it just means that you don't need it anymore
when you're using Cocoa.
The existing code that performs the work of an application
can remain as C++ code and can be called as needed in your
application.
The only C++ code that needs rewriting is any interface-related
code that does things that Interface Builder and Cocoa don't
do for you. These types of tasks fall into two general catego-
ries:
1. Things that Interface Builder and Cocoa don't do and
that you want to do because you're bringing a precon-
ceived other interface along with you. In this case, for-
get it. Use the proper interface.
2. Things that Interface Builder and Cocoa don't do that
are specific to your needs and that you must add. Al-
though this code may live in your interface classes, it
is truly application specific; you can call C++ code as
needed. If it really is interface-related (involving
drawing, for example), you may need to rewrite it to
use the Quartz API, but you can access that from C.
This is actually a very small amount of code for almost
everyone. (For most people, it is no code at all.)
If you are converting an existing
application to Mac OS X, you may choose to leave its function-
ality in C++ while using Interface Builder and Cocoa (together
with Objective-C or Java). Depending on who has what skills
(as well as the magnitude of the code base), it may be desir-
able to do a full-fledged port. This is an individual decision
that must take into account deadlines, individual expertise,
and other pertinent factors.
Objective-C++ is a front end to the Mac OS X version of the
GCC compiler. It was introduced in Mac OS X 10.1. It allows
you to use Objective-C and C++ together. As you have seen,
the languages are very different, so their integration has been
a delicate task. It is essential because there are large bodies of
legacy code (usually C++) that people want to integrate into
new applications. Also, although the goal is to eventually
make all of the Mac OS X features available from both Carbon
and Cocoa, many features of Mac OS 9 and earlier are avail-
able only in Carbon as of the initial Mac OS X releases. For ei-
ther of these reasons, you may need to use Objective-C++.
The Objective-C++ integration is designed to function at this
very high level; you cannot call Objective-C objects using C++
syntax, but you can call Objective-C objects using Objective-C
syntax (or C++ objects using C++ syntax). You cannot create
inheritance structures that cross language bounds: descen-
dants of C++ objects cannot be Objective-C objects, and vice
versa.
You can create objects with instance variables which are
pointers to objects that are actually implemented in either
C++ or Objective-C. You must use the appropriate language
syntax in accessing these pointers to C++ or Objective-C ob-
jects: that is, you use C++ or Objective-C to make the calls. As
a result, the individual lines of C++ or Objective-C code are
mingled within your Objective-C++ file.
Keywords in the two languages often differ: s e 1 f (Objective-
C) and t h i s (C++) are both ways of referring to an object it-
self. Because the syntax from both languages may occur in
Objective-C++ files, the list of reserved words for Objective-
C++ consists of the union of the two languages' reserved
words. You use the terms separately--s e 1 f and r s are still
language-specific--but you may use both of them in appro-
priate contexts within the same file.
Project Builder invokes the Objective-C++ front end automat-
icaUy for files with a suffix of .M or .mm.
Today, C++ is one of the most popular programming lan-
guages. Existing (and new) code written in C++ can be used
within Mac OS X to implement application functionality as
needed. The use of C++ in conjunction with Cocoa and Inter-
face Builder is circumscribed; however, it is not so much a
question of rewriting C++ interfaces as of jettisoning existing
C++ code in favor of the frameworks and no (or little) custom
interface code.
The primary framework for Mac OS X is Cocoa. It consists of two
kits~Foundation and the Application Kit (AppKit). The AppKit
classes provide the entire Aqua interface as well as most of the func-
tionality that you deal with.
In this chapter, the fundamentals of Cocoa~both in AppKit and
Foundation--are described. A lot of this discussion focuses on how
it works: You do not often code or override the methods or objects de-
scribed here, but this is how Cocoa does its jobs.
Many of the concepts pop up here and there in the work that you do
have to do--for example, responders, events, and actions are critical
to your work. You use them repeatedly as they are implemented in
Cocoa (that is, without overriding them). Some people like to under-
stand the architecture and concepts before looking at code; other peo-
ple want to examine code and then look at the concepts that lie
beneath it. If you are in the second group, you may want to read Part
III before continuing with the chapters in this part.
Two general concerns apply to the Cocoa terminology in ad-
dition to the general principles of object-oriented program-
ming:
0 Certain terms and conventions (services, connections,
and outlets, for example) make it easier for you, your
users, and consultants to use Mac OS X to construct
customized applications and solutions.
0 Dynamism in the forms of dynamic typing and bind-
ing further expands the flexibility of Cocoa and makes
much of Mac OS X's customizable interface possible.
As is often the case, nothing forces you to make your objects
usable in this w a y - - y o u can decree what connections and in-
terfaces exist and freeze them for all time. Likewise, you can
ignore dynamic binding and typing, keeping control over
your application and dictating how it is used.
When it comes to delivering value to users and customers, it
is far better to provide flexibility that allows them to do what
they want than to keep things "off limits" so that they don't
cause damage. Use the Cocoa error-handling routines and
run-time facilities to prevent, detect, and correct errors rather
than deluding yourself that preventing user access to your ob-
jects' functionality will yield a more stable system.
Everything is now an object, and sometimes their meanings
blur. At run time, an object is an instance of a class~a struc-
9
ture that has access to that class's methods and that has data
values of its own. Other instantiated objects of that class have
access to the same methods and have their own data values.
The class itself is the definition or template from which each
object is instantiated. In Cocoa, the class is a run-time object of
type Class; that object can instantiate an instance of its class.
Thus, you might have a class defining an object of type Barn.
At run time, an instance object of type Class exists for Barn.
The Barn Class object can instantiate instances of barn such as
etc.
If you have p r o g r a m m e d for Mac OS, events and the event
loop are familiar to you. Events may be generated by user ac-
tions (mouse clicks, mouse movements, etc.); they also can be
generated by the system either directly or indirectly in re-
sponse to user actions or for other reasons. For example, Co-
coa supports the concept of periodic e v e n t s - - - e v e n t s that are
sent at specific intervals to an application in response to a sin-
gle request from it. Periodic events may be used by a w i n d o w
during mouse tracking.
Actions have more semantic meaning than events and often
correspond to user commands. Cut, copy, paste, capitalize, in-
dent, and page down are typical actions in Cocoa. Events are
generated by the operating system in response to a user's in-
teraction with the interface; actions are generated by objects
such as windows, views, menus, and controls in response to
lower-level events.
In Cocoa, an object that can handle events and actions is a re-
sponder--usually a descendant of NSResponder. Applica-
tions, views, windows, and controls are all descendants of
NSResponder and therefore can respond to events and ac-
tions.
The dispatching of actions differs somewhat from what you
may be used to. In frameworks based on static languages such
as C++ (MacApp and PowerPlant, for example), each object
that can handle an event (applications, views, windows, and
controls) is given a chance to handle every incoming event.
Usually this is accomplished in a method such as D o M e n u -
Command, in which a gigantic switch statement has a case for
each command that the object could handle. Commands that
fall through the switch statement encounter a default block,
which routes the command to the next object.
In Cocoa, the process is more direct. Given an action that
needs a response, NSApplication finds a responder that im-
plements
One of the most significant features of the Carbon libraries is
their implementation of direct dispatching of e v e n t s ~ b y pre-
cisely this mechanism. As a result, MacApp and other Car-
bon-based applications can now provide the same efficiency
of event handling that Cocoa does.
Just as in other frameworks, events and actions are passed
along from one element of the framework to another until one
of them handles the request. This is done through a linked list
of responder objects~each one points to its next responder or,
if there is none, to null.
The framework takes care of following the responder chain
through all of its elements. Typically, part of a w i n d o w (a
view or a control) is the first responder; if it cannot handle the
event or action, it is passed on to its next r e s p o n d e r ~ i t s su-
perview (the view in which it is contained)~until its w i n d o w
is reached.
At that point, if the event or action has not been handled, the
application moves on. There are normally three parts of the
responder chain (each of which consists of its own linked list):
0 The Cocoa key w i n d o w is the w i n d o w to which all
events and actions are directed.
Q The main w i n d o w is the content w i n d o w of data cur-
rently being worked on. The key w i n d o w often is the
content window; however, w h e n a floating panel is in-
terposed between the main w i n d o w and the user, that
panel becomes the key window. (This is one more step
in the continuing saga of how to manage floating pal-
ettes.) The application sends unprocessed events and
actions from the key w i n d o w to the main window.
0 The application uses its own responder chain to at-
tempt to process the event or action.
As in most other frameworks you may have used, this is a crit-
ical part of p r o c e s s i n g ~ a n d one that you can safely ignore
most of the time.The framework will manage the responder
chain in most cases.
Note, too, that actions can be dispatched directly to objects
rather than going through the responder chain. When you
connect an interface element to an object in Interface Builder,
the method that you select is activated on demand. Thus, if
you have a document (not an NSResponder), it can be directly
connected to the Save menu command.
As the penultimate step in each part of the responder chain
(key window, main window, application), a delegate of the
w i n d o w or application is given a chance to handle the event
or action. The delegate---which must be an NSObject~need
not be a descendant of NSResponder. The w i n d o w or applica-
tion has a chance to forward the action or event to any object
that it chooses (that presumably can respond to the event or
action). If that, too, fails, then the ultimate step in each part of
the responder chain is to pass on to the next p a r t - - f r o m the
key w i n d o w to the main w i n d o w to the application.
The use of a delegate is a very important part of the Cocoa ar-
chitecture. For your application object (or a w i n d o w or a
view) to implement some functionality (responding to a mes-
sage or a method call), it need only have a delegate that can do
so. In other architectures, the application object (or w i n d o w or
view) would need to be subclassed to add the appropriate
message or method call.
An object often needs a reference to other objects with which
it has to deal: A view may need to be able to communicate
with its window, two views may need to mutually update
data fields, etc. An outlet is just such a reference. Interface
Builder can find such instance variables in your class defini-
tion and allow them to be manipulated by you or your users.
It finds outlet instance variables by looking for the keyword
IBOutlet in your header files (IBOutlet is defined to map to
nothing, so it does not interfere with the compilation process).
Thus, the following declaration in a header file will be as-
sumed by Interface Builder to be an outlet:
With your outlets visible to Interface Builder, you can then
connect them to graphical elements in your interface by using
connections.
You connect outlets to interface objects. For example, a data
entry field called "city" might be an outlet that is connected to
a specific text field in your interface. Because Interface Builder
can recognize your outlets, it can display the list of outlets for
your object, allowing you to connect them to interface ele-
ments. Again, this differs from static language-based frame-
works in which there is always a little snippet of code that you
have to execute at run time to link the text field to the instance
variable "city."
Connections are also made for actions--and here the direction
of data flow is critical. Action connections are made from con-
trol objects (such as buttons) to the objects that you create. Ac-
tions not only have a source and destination, but also have a
message that corresponds to a method of the receiving object.
Thus, you can create an action connection from a button to an
object you create and have it process the appropriate message
of your object.
Interface Builder relies on methods of the form
to find your object's actions. It generates a list of possible ac-
tions that your object can perform by compiling all of the ac-
tion names into a list.
Like IBOutlet, IBAction maps to nothing, so it does not inter-
fere with the compilation of your header file. Also, as with
IBOutlet, IBAction was not present in the first versions of In-
terface Builder. Thus, you will find old-style action methods
in some existing code:
This section provides an overview of the structure of the App-
Kit classes. They are grouped into nine areas:
1. Interface
2. Fonts
3. Graphics
4. Color
5. Documents
6. Printing
7. Operating system support
8. International support
9. Interface Builder support
If the sheer size of Cocoa and its classes is daunting, consider
that most of its classes just work---you don't have to worry
about them. When you look at these areas, you can quickly see
that many of them are probably not going to concern you.
Fonts, for example, are set by the user in the Font panel and
used by text objects~automatically. That's one area you
probably do not have to worry about.
Likewise, color for text and other interface elements is set us-
ing the Color Picker, and you do not have to worry about it
unless you need to implement a non-standard interface
(which is probably not a good idea). The objects in question
have their color choices set through the default behavior of in-
terface elements. For many developers, international support
is not an issue: Custom-written software developed for a
school in France need not recognize the needs of a Mandarin
speaker (but the capabilities are there if needs change).
Some of the more important Cocoa classes are described in
brief in this section. They (and others) are discussed in more
detail in Part III of this book.
By far the largest collection of classes is used to implement the
Aqua interface. (In most frameworks that implement graphi-
cal user interfaces, the interface objects predominate.)
One problem with object-oriented frameworks has always
been the fact that developers can override objects. True, this is
one of the big advantages of such frameworks. When it comes
to the interface, however, overriding standard elements has
contributed to variations in functionality that confuse users
and to difficulties in maintaining code.
Cocoa provides a number of ways to modify and extend inter-
face elements without overriding them. In particular, delega-
tion and protocols (such as MacApp behaviors) allow events
to be passed off to custom-written objects that can provide
functionality while leaving the underlying objects unscathed.
If you are used to overriding objects (particularly interface ob-
jects), reconsider this choice before you do so with the Cocoa
interface classes.
The interface classes are categorized into four major groups.
Three of them are centered on objects that are descendants of
NSObject itself. The fourth is a collection of objects that han-
dle text.
User-controlled applications are driven by events
that normally are generated by the user. The most common of
these are keystrokes, mouse movements, and clicking. Other
events are generated by external events (network messages,
for example) or by Cocoa or Mac OS X itself (periodic events
in Cocoa fire on a regular basis once you have set them up).
An application needs to inspect each event that is sent to it; it
can decline to do anything about the event, but it must exam-
ine each event that is sent to it.
NSResponder NSResponder objects can appear in the re-
sponder chain; they respond to events. Here you find the ba-
sic elements of a Cocoa application: windows, views, and the
application itself. (In MacApp, the TEventHandler class is a
common ancestor of views and the application object.)
NSCell Cells are relatively lightweight objects that can dis-
play text or images. They can also manage mouse tracking, se-
lection, menus, actions, keyboard events, and the cursor. In
this respect, they are like responders in general and views in
particular.
However, cells are not responders or v i e w s ~ t h e y descend di-
rectly from NSObject. Controls (descendants of NSControl
such as NSButton) often have a cell associated with them to
handle these generic activities. NSControl does descend from
NSView and thus from NSResponder; it participates in the re-
sponder chain as appropriate and often passes off the process-
ing of a specific message to an associated NSCell.
The amount of code needed to properly handle text is
enormous. Even without considering the demands of multi-
ple languages and scripts, laying out text automatically
(much less in response to user commands) is daunting. Users'
expectations now are for the presentation of text on computer
displays that matches or exceeds sophisticated typesetting on
paper.
NSText and NSTextView are descendants of NSView (and
thence of NSResponder). Both are designed to provide so-
phisticated text management so that you should not need to
override them.
NSText is the more basic object: It displays text and imple-
ments actions allowing users to modify text styles. It manages
wrapping of text across lines, and it can display graphics as
part of RTF text. It implements clipboard support, including
copying and pasting of fonts (as well as of text).
NSTextView provides further implementation of NSText (in
fact, it is the object that you normally use in your applica-
tions). NSTextView provides additional support for rulers,
services, and the storage of attachments (such as graphics).
O t h e r ClassesOther interface classes handle menu items,
status bars, toolbars, and the other Aqua interface elements.
The font classes~NSFont and NSFontManager~are used by
the Font panel, which users access to change their text font.
The classes provide access to font information, but you rarely
need to use them.
The graphics area provides so much functionality that here,
too, you may never need to get involved. Three of its classes
are of particular interest.
NSImage is the general image object. It reads im-
age data and keeps track of multiple representations of it. The
NSImage and NSImageRep structures are what makes it pos-
sible to create interface elements that display images without
apparent regard to their type.
An NSImage object contains an array of one or
more NSImageRep objects. Standard objects are listed here:
9 EPS images
9 PICTs
9 Bit-mapped graphics
9 PDF images
9 Images cached in m e m o r y (but with no instructions al-
lowing them to be regenerated)
9 Custom images that your application can create
When an NSImage needs to draw itself, it chooses from
among its NSImageRep objects based on these criteria (in the
following order)"
9 Color
9 Resolution
9 Depth (pixel depth or sample)
NSMovie The NSMovie object can play QuickTime movies.
Some of the QuickTime code exists here, but all of QuickTime
is not available to this object.
Other graphics classes let you access cursors
and the screen as well as OpenGL and the graphics environ-
ment.
Like font objects, the color classes just work in most cases. NS-
Color and NSColorPicker are in this area; all interface ele-
ments work properly with them and you do not normally
need to be concerned.
Documents are an area in which you do need to be very con-
cerned if your application stores data. Note that the document
architecture in Cocoa is much lighter weight than that of ei-
ther MacApp or PowerPlant. In both of those frameworks, the
document object is large and central. In Cocoa, the NSDocu-
ment object did not even exist until the late 1990s.
The NSDocument object contains your docu-
ment's data. It is a descendant of NSObject~not, as in frame-
works such as MacApp, an event handler. However,
documents can receive first-responder calls to save, revert, or
print themselves.
The primary purpose of the NSDocument object is data man-
agement. If you use documents, you always override NSDoc-
ument.
or more than one document type, you use an NSDocu-
mentController. This object intercepts File menu commands
such as New or Open so as to carry them out.
In most cases, you do not need to override NSDocumentCon-
troller; its default behavior works.
NSFileWrapper NSFileWrapper provides the in-memory
versions of disk files. The default NSDocument and NSDocu-
mentController methods normally handle file wrappers prop-
erly.
You rarely override the printing objects in Cocoa.
A grabbag of objects provides support for help, copy-and-
paste, spell checking, sound, and the desktop.
The pasteboard supports copy-and-paste on
Cocoa. This object has had a difficult life when it comes to no-
menclature. On the original Macintosh, it was referred to as
the scrap or desk scrap; for users, it was the clipboard.
In Cocoa, the pasteboard structure is more complex than that
found in other environments. At least five separate paste-
boards exist to handle different types of shared objects:
1. Fonts
2. Rulers
3. Find text
4. Drag-and-drop data
Other objects
Most interface elements handle copy-and-paste properly, so
you may never need to get involved with pasteboards.
The workspace object exists for each applica-
tion. You use it to launch applications, copy files, and find the
appropriate icons for files. It is somewhat like a programmer's
Finder.
The input manager classes provide support for non-Roman
alphabets.
Three classes provide support for Interface Builder and its dy-
namic interface creation mechanism: NSNibConnector and its
decendants, NSNibControlConnector, and NSNibOutletCon-
nector.
The Foundation framework provides the underpinnings for
the AppKit framework. In the Carbon environment, the Core
Foundation library lets Carbon developers get to the Founda-
tion functionality. (See Chapter 9 for more details on the Core
Foundation.)
Foundation's classes are grouped into 10 areas:
1. NSObject
2. Values
3. Strings
4. Collections
5. Operating system services
6. Notifications
7. Archiving
8. Objective-C language services
9. Scripting
10. Distributed objects
NSObject and NSProxy are the basic objects from which all
other objects descend~both those that are implemented in
Cocoa itself and those that you create. This section describes
NSObject in detail. In addition to the NSObject class, the
NSObject protocol is also discussed here.
NSProxy, which supports objects that do not exist (such as ob-
jects that have not yet been instantiated) as well as distributed
objects, is discussed in the final section of the Foundation
framework.
The issue of a common base object
from which all other objects descend has been debated for a
long time in the object-oriented community. The main disad-
vantage of a common ancestor is that a change to its structure
requires recompilation of all objects that descend from i t ~ t h e
fragile base class problem. Of course, this argument loses
most of its potency in a world where the fragile base class
problem has been wrestled into submission (such as the dy-
namic world of Cocoa).
The argument in favor of a common base object is that all ob-
jects in the environment share certain characteristics and that
you can rely on any object that you use to be able to perform
certain tasks. Although static languages such as C++ let you
inquire as to an object's class and dynamic languages let you
inquire in more detail about not only the object's class but also
the methods that it implements, it is still easier and more effi-
cient to know that a certain set of tasks can be performed by
any object with a certain ancestor.
This dogged problem is partly caused by the layering of ob-
ject-oriented frameworks on top of operating systems. There
is a critical barrier between the world of objects and the world
of nonobject processing. In almost all cases, hardware does
not deal with objects--in fact, it rarely deals with even such
sophisticated concepts as data structures. It just moves bits
and bytes around.
As you move from the hardware to the operating system, the
bits and bytes are aggregated into data structures (strings, col-
ors, files, etc.). Then, in what is traditionally called the appli-
cation layer, a framework takes the data structures and
encapsulates them into objects with which it works.
NSObject instance has a variable called i s a. It points to the
class object of that instance's class, and it is the route by which
Cocoa is able to handle many of the introspective queries. In
Java, this issue is handled by standard Java calls.
ing in Java rather than Objective-C need to note that a handful
of Cocoa/Java classes do not descend from NSObject. These
classes, such as NSDate and NSException, are implemented
as descendants of the Java Object base class rather than as de-
scendants of NSObject. In addition, some Objective-C structs
(such as NSRect) are native Java classes.
Furthermore, NSObject in Java descends from the Java Object
base class. As a result, some of the most primitive Objective-
C methods (primarily those dealing with instance creation
and initialization) are not present in the Java NSObject imple-
mentation; instead, the native Java Object methods that corre-
spond to these are used.
NSObject~through its class and its
protocol~provides basic functionalities shared by all objects
in the Cocoa framework. These functionalities fall into the fol-
lowing categories:
They provide means to initialize the class and then to
create and destroy instances of it. (This process is re-
ferred to generically as fabrication.)
Methods provide for introspection of the object~the
class and superclass to which it belongs, to which
what messages it responds, etc.
Identification of a specific object~is this object the
same as that one, for example~is supported. Identifi-
cation differs from introspection in that introspection
deals with the attributes and characteristics of the ob-
ject, whereas identification deals with recognizing a
specific object.
Message handling is provided by NSObject, chiefly us-
ing the perform method.
Memory management is implemented so that objects
can be shared when needed but removed from memo-
ry when no longer in use.
NSObjects can be archived and unarchived; this is
done with their own methods and also by using the
NSCoder protocol that NSObject adopts. The process-
es are grouped under archiving and serialization.
9 Error handling is supported by NSObject.
Because of the significance of NSObject, each of these func-
tionalities is described in more detail in the following sec-
tions. Most of the NSObject methods are described in this
section.
Allocation and initialization are used together
w h e n you manually create an object. You normally use a fac-
tory method that directly creates (allocates and initializes) an
instance of the class required.
In Objective-C, you allocate an object using a Class method;
you initialize it with an instance method.
Conceptually, an invocation consists of:
a n O b j e c t is an instance of the class myObjectClass; it is first
allocated and then initialized. The second statement appears
to replace anObject with itself: That is, its i n i t method is
called and the result is returned and overwrites anObject with
the result of i n i t. This coding is necessary because the i n i t
method can second-guess your initial object creation and re-
turn a substitute object (perhaps a more specific subclass of
myObject than the general one you created).
In reality, most allocation and initialization are done with a
single line of code that calls both the Class and instance meth-
ods:
This line of code appears over and over in Objective-C Cocoa
programs.
Objects that are located farther d o w n the inheritance tree from
NSObject m a y have more complex i n i t m e t h o d s that take
parameters or that have different names. For example, NS-
View has an initialization m e t h o d that takes the view's
framerect into account:
Within the implementation of such initialization methods, a
call to
m u s t be m a d e (or to a comparable initialization method).
These inherited calls m u s t be m a d e so that initialization pro-
ceeds all the w a y up to the basic NSObject i n i t method. (The
absence of these inherited calls is a frequently encountered
bug. It is particularly insidious because the object is allocated
and appears non-nil in a debugger, but w h e n you attempt to
use i t - - t h o u s a n d s of lines of code later--it is corrupted.)
H a v i n g allocated an object, you m u s t deallocate it w h e n you
are done with it:
You override this m e t h o d if you have data structures to re-
lease or if you have subsidiary objects to release. It is called
from r e 1 e a s e and au t o r e 1 e a s e (methods of the NSObject
protocol, discussed later in this chapter).
Thus, in Objective-C, you call a l 1 o c and i n i t to create an
object. You override d e a l l oc; it will be called w h e n needed.
In Java, you use standard m e t h o d creation and construction
calls to create instances of classes.
The n e w function creates an instance of a class, as in
You do not explicitly call an i n i t method; rather, a construc-
tor is automatically invoked based on the name of the class
and the parameters passed in the new call. Thus, Java would
expect to find a method such as the following for it to call
w h e n you execute the previous line of code:
Just as in Objective-C, the call to the inherited constructor is
essential. The call to new and the constructor can take match-
ing parameters, such as the following pair:
Parameters to the constructor can be passed along to the su-
perclass's constructor, used to set instance variables, or
b o t h - - a s is the case here.
Java handles garbage collection, so you do not have to call a
d e a l 1 o c method. A related concept--the f i n a l i z e method
of Object--exists, and you can override it if necessary. It is
called during garbage collection just as an object is about to be
destroyed. Java will automatically reclaim all of the object's
memory, so you do not need to do anything about that. If you
have m e m o r y structures or other data of an object that Java
will not recognize, however, you may need to provide an
override of f i n a l i z e .
One frequent Cocoa use of f i na 1 i z e is to remove an object
as an observer of notifications (since the object will no longer
exist). Here is such a f i n a l i z e method (they are scattered
throughout Cocoa Java programs).
Introspection Particularly in the dynamic environment of
Mac OS X, it is important that objects be able to examine them-
selves. Some of the compiler-time error checking you may be
used to in less dynamic languages does not occur, and rather
than allow a program to crash or misfunction, you need to do
that checking at runtime.
In Java, this is done by using the Class class (that is, the class
named "Class"), and the term "reflection" is used rather than
"introspection." The relevant methods include g e t s u p e r -
For example, consider the code to discover whether a method
exists in a given class. First, you obtain the class; one w a y to
do this is from an instance of the class.
Because g e t C I a s s is a method of Object, all Java objects re-
spond to it appropriately. Next, if you want to see if that class
responds to a given method, you can use the following code:
Objective-C has methods that are comparable to the Class and
java.lang.reflect methods in Java. Here is one that is similar to
the Java example just shown and that is the one that you use
most often: the test to see whether an object responds to a giv-
en message or selector (that is, whether it contains a specific
method).
The selector is the complete description of the method you are
looking for including its name and any optional parameters.
The following are all selectors:
Identification routines let you compare and
identify objects based on their content. Here, too, there are
some differences between Objective-C and Java. Perhaps the
most obvious one is the w a y in which you refer to an object it-
self: use self in Objective-C and this in Java. These two lines of
code are comparable:
The tests for two identical objects are also different in Objec-
tive-C and Java:
Note that these tests are methods of NSObject in both Objec-
tive-C and Java, but they have different names ( e q u a l s is a
method of Object in Java, and is overridden by NSObject so as
not to drive Java programmers mad).
What is important to note is that in your descendants of
NSObject in either language, you can override e q u a l s or
i s E q u a l . This means that you can determine what equality is
for specific objects.
While all object-oriented languages and
frameworks can handle messages (whether they are called
messages or function calls), one of the very significant advan-
tages of Cocoa and its dynamic nature is that it can reroute
messages on the fly. The previously noted methods r e -
s p o n d s T o S e l e c t o r and the comparable Java code dis-
cussed previously let you find out if an object can handle a
message. If it does, you can then cause the method to be in-
voked (or the message to be sent, depending on your semantic
preference).
If, in Java, you have found a method using the code shown
previously,
you can invoke that method by using the Object i n v o k e
method:
To actually do this, you should catch the possible exceptions:
In Objective-C, you can do a comparable feat. You rely on the
performSelector m e t h o d of Objective-C and NSObject; it
takes a single p a r a m e t e r - - a (SEL) that is usually exactly w h a t
However, the framework will normally do m u c h of this w o r k
for you. If an object receives a message to which it cannot re-
ply (that is, it is asked to perform a m e t h o d or function that it
does not have), it is then sent a n e w m e s s a g e - - f o r w a r d I n -
v o c a t i on. The original message is w r a p p e d in an NSInvoca-
tion* object. You can extract the message to use in a call to
Memory Management M e m o r y m a n a g e m e n t is an important
parts of m o d e r n frameworks and languages. Too m u c h time
has been spent tracking d o w n m e m o r y leaks and mysterious
crashes from data structures that were not allocated w h e n
n e c e s s a r y - - o r were pulled out from u n d e r n e a t h code that as-
s u m e d they were there.
In Foundation, the process is m a d e as simple as possible.
W h e n you w a n t to make certain an object is a r o u n d at a later
time, you send the r e t a i n message; you balance each r e -
r message with a r e l e a s e message. In a great m a n y cas-
es, this is done automatically for you. For example, the
NSArray object allows you to p u t objects into an array that
can then be m a n i p u l a t e d with its searching and sorting meth-
ods. NSArray calls r e t a i n for each object it adds to its array;
it calls r e l e a s e w h e n it removes objects from the array. In
this way, an object in an NSArray can never accidentally be
deallocated while it is in the array.
Autorelease pools provide an even easier w a y to m a n a g e ob-
jects. Here, you send the a u t o r e 1 e a s e message to an object
instead of a r e t a i n message; it is automatically added to the
current autorelease p o o l - - w h i c h is merely a collection of ob-
jects that can be released at a given time. When the pool itself
is released, each object in the pool is sent a r e l e a s e mes-
s a g e - - y o u don't have to balance r e r a i n and r e 1 e a s e calls.
A single autorelease pool exists for the life of your application,
although you can create others (and usually do for each
thread in a multithreaded application). As balancing r e t a i n
and r e 1 e as e calls is a potentially time-consuming program-
ming chore, using a u t o r e l e a s e is a valuable tool. The dis-
advantage of a u t o r e l e a s e is that the r e l e a s e messages
are not sent until the entire pool is deallocated. Thus, if you
have an object that you want to retain and could release al-
most immediately, using a u t o r e l e a s e will keep it around
until the current autorelease pool is deallocated.
The actual mechanism that is used is a reference count in each
object that is incremented by one for each r e r call and
decremented by one for each r e l e a s e call. When the count
falls to zero, the object is deallocated.
In Java, the java.io.Serializable in-
terface lets you write out objects without further ado. Its sub-
interface, java.io.Externalizable, lets you customize the
reading and writing.
In Objective-C, NSObject provides basic support for archiving
and distribution. Archiving refers to placing representations of
objects on disk; distribution refers to copying objects to other
address spaces.
Archiving relies on NSCoder objects that are discussed in
"Archiving, Serialization, and Distribution" on page 474. Ta-
ble 7-1 shows the archiving methods of NSObject in Objec-
tive-C. In practice, you frequently use NSCoder (which is
available both in Objective-C and in Java) to create serialized
data that you then store in dictionaries (see "NSDictionary"
on page 137).
Return a Class object to be used
during archiving or coding. The
default is the object's own Class.
Returns an id of an alternative ob-
ject to archive by a n A r c h i v e r
(NSArchiver*). This allows you to
read and write less complex ob-
jects than your run-time objects.
The counterpart of the replace-
ment Object methods. Its single ar-
gument aC o d e r (NSCoder*) has
just created the object; you can
substitute another.
Returns an id of an alternative ob-
ject to encode by e n c o d e r
(NSCoder*). This allows you to
read and write less complex ob-
jects than your run-time objects.
You can provide a version for ob-
jects that are archived. This helps
you manage change in your soft-
ware.
Set: a n I n t (int).
Get: returns an int.
Objective-C, NSObject itself has only one
m e t h o d to directly h a n d l e e r r o r s - - d o e s N o t R e c o g n i z e S e -
1 e c t o r. It is called by the run-time e n v i r o n m e n t w h e n a mes-
sage sent to the object cannot be processed.
t i on to attempt to process the message before aoesNo C R e c -
o g n i z e S e l e c t o r is called.
N S l n v o c a t i o n This small object wraps a message that cannot
be processed in Objective-C. Note that messages being for-
warded must have a fixed number of arguments; some meth-
ods (such as NSArray's i n i twi t h 0 b j e e t s ) that use variable
numbers of arguments are not allowed.
These objects include dates, numbers, and the like. Here is
where you are most likely to find differences between the Ob-
jective-C and Java versions of Cocoa.
The Java implementation, for example, contains an NSRange
object~a descendant of the primal Java Object class. In Objec-
tive-C, NSRange is a type. NSRange consists of two integers,
and the overhead of creating such a small object as an object
(rather than a type) in Objective-C is not worth the effort.
NSRect, NSPoint, and NSSize are treated similarly: They are
objects in Java, and they are types in Objective-C.
NSData is an undifferentiated collection of bytes. It
is frequently used as a return value from a method. Another
method casts the NSData object to a more specific type.
NSValue NSValue is an Objective-C class that wraps a sim-
ple value (an integer, for example). It exists so that such values
can be used in places where objects are required, such as with-
in an NSArray object. It is not needed in Java, since integers
and everything else are objects in that language.
The Objective-C NSString class and the native Java string
class are both used to manage strings. Two Cocoa classes are
of particular interest: NSFormatter and NSAttributedString.
NSFormatter NSFormatter objects~available in both lan-
guages--edit, display, and validate string entries in cell ob-
jects. (Cells contain controls such as text fields.) Two standard
formatters~NSGregorianDateFormatter and NSNumberFor-
matter--are provided. You can override NSFormatter your-
self to provide additional functionality.
Note that NSFormatter objects take localization rules into ac-
count. Thus, you probably do not need to create your own NS-
Formatter object to implement those features.
NSAttributedString An NSAttributedString adds styling at-
tributes to the characters of a basic string (NSString in Objec-
tive-C or string object in Java). It contains such a string as part
of its data structure.
Collection objects manage multiple data values.
In traditional programming, arrays and iterators
were widely used. With the advent of object-oriented pro-
gramming, various collection objects have been devised that
incorporate the iterators. Many of them also include sophisti-
cated searching mechanisms.
NSDictionary The NSDictionary object is a very powerful
construct of Cocoa. It is just a set of key/value pairs, but it can
be quickly accessed and can be stored to and retrieved from
disk (see "Dictionaries" on page 377 for an example of its use).
NSDictionary objects are used extensively in Cocoa. Perhaps
because of their name, many people think they are appropri-
ate for large amounts of data. In fact, they are useful for stor-
ing any amount of data that can be named. (Because
NSDictionary keys must be unique, naming is important.)
Unordered sets of data are supported by the NSSet
class.
Foundation operating system services include locks, tasks,
and threads. For most purposes, you can let the frameworks
take care of these for you.
Notifications are part of the Cocoa messaging system: One ob-
ject can register its interest in another object and certain
events. An object posts a notification when it does something;
Cocoa takes care that the appropriate other objects are noti-
fied.
Notifications are used for such events as window movement
or resizing, application launching or activating, and the like.
What is important about notifications is that the posting of the
notification and the receipt of the notification are separate; an
application does not notify individual objects that a window
has moved. See "Notification" on page 404 for more informa-
tion.
The NSCoder class and its descendants, NSArchiver and
NSUnarchiver, are used to move objects from memory to files
or to flattened data structures suitable for writing or transmit-
ting to other computers. They provide recursive processing,
so that an entire collection of objects (or graph of related ob-
jects) can be reconstituted at a later time or at another location.
NSUndoManager, NSException, NSAutoreleasePool, NSAsser-
tionHandler, and several other utility classes provide support
for constructs of Objective-C itself.
Support for AppleScript is located in the Foundation frame-
work (not the AppKit). Scripting is described in Chapter 28.
Finally the Foundation framework lays the basis for manag-
ing objects across a network. The key to this is the NSProxy
object.
NSProxy, like NSObject, is a base object or root class. It adopts
the NSObject protocol, so it provides all of the functions of in-
trospection etc.),
On its own, NSProxy has seven methods. In addition to the
standard allocation and deallocation methods, it has the f o r -
When an NSInvocation is received to which it cannot respond
(and that is any invocation), it passes it on to the object for
which it is standing in. At that moment, it may be necessary
for that object to be instantiated, or for a link to an object
somewhere else to be established. The methods of NSProxy
are shown in Table 7-2.
The basic m e t h o d to allocate the
object.
Called from a r e 1 e a s e method.
You override this m e t h o d if y o u
have data structures to release or if
y o u have subsidiary objects to re-
lease.
Returns the Class object.
You pass
(NSInvocation*) on to the object
that the NSProxy is r e p r e s e n t i n g - -
possibly instantiating that object at
the time.
You override this method to re-
turn the NSMethodSignature* for
a S e i e c r o r (SEL). Normally,
you call the me t h o d S i g n a -
representing--possibly instantiat-
ing that object at the time.
Returns an NSString*; the default
implementation returns the class
name in the string. You can over-
ride it to provide additional infor-
mation to debuggers.
Because NSProxy is a base class and not a descendant of
NSObject, it has only the NSObject protocol methods avail-
able.
If you have used other frameworks, you will be struck with
how similar Cocoa is to them. After all, graphical user inter-
faces rely on menus and windows, and there's only so much
you can do with them!
Cocoa differs from other frameworks in its dynamism, and in
the fact that its class structure is much less deep than it is in
some heavily overridden frameworks (particularly MacApp).
Furthermore, its utility objects such as dictionaries allow for
data hiding (encapsulation) as well as very fast development
since the single data-handling structure can be accessed as
needed.
Carbon is a set of libraries that constitute a framework (in the Mac
OS X sense of the word). It is most notable for the ways in which it
differs from Cocoa:
9 You can program Carbon applications in C++.
You can modify existing applications to run in Carbon, tak-
ing advantage of many of the Mac OS X features.
Carbon applications can run on both Mac OS X and on leg-
acy systems~Mac OS 8.1 and later and earlier.
This chapter shows you how Carbon fits into Mac OS X. It next
shows you the structure of the Carbon frameworks, and it then ex-
plores the Carbon event model and how it differs from older pro-
gramming styles on the Macintosh.
Apple's first attempt at moving to the UNIX-based world that
is n o w Mac OS X met with heavy resistance from developers.
Apple provided an environment that w o u l d run then-existing
software (it is n o w called Classic, then it was Blue Box), but
the new features of the operating system were to be available
only to freshly written applications using the Rhapsody
framework (which is now Cocoa).
The gap between Blue Box and Rhapsody was just too large
for people to swallow. After listening to customers and devel-
opers, Apple added Carbon to the picture.
Perhaps what is most important about Carbon is that it is not
the Classic environment. In the Classic environment on Mac
OS X, applications run as if they were running on Mac OS 9
(they are, in fact). They have that interface, and they have
none of the modern features of the Mac OS X operating sys-
tem such as protected memory. While a feature such as pro-
tected m e m o r y is a behind-the-scenes issue, the look and feel
of the applications makes it clear to most users that they are
running in the Classic environment.
There are some user interface differences between Aqua and
Classic that can be annoying if you have to switch back and
forth between them (it is the switching that causes the prob-
lem). When coupled with the lesser stability of the Classic en-
vironment w h e n compared to Mac OS X, it is clear that Classic
is a remarkable achievement, but it still is a second-class envi-
ronment in which to run programs.
Carbon allows applications to access the features of Mac OS X,
but Carbon applications do not run in the Classic environ-
ment. That is the most significant difference from a user's
point of view since it is the most noticeable.
On Mac OS 9 and earlier, executable code is stored in code
fragments; it is unpacked as needed by the Code Fragment
Manager (CFM). The format of these files is referred to as PEF
(Preferred Executable Format), but CFM is also sometimes
used to refer to them.
Before the PowerPC chip powered Macintosh computers, a
separate format was used. Code segments were stored in the
resource fork of two-forked files, and they were loaded as
needed.
On Mac OS X, the preferred format is Mach-O, but PEF files
can also run. Mach-O files cannot be executed on Mac OS 9
and earlier.
In addition to the question of which executable file format can
run where, the question of which development environment
can generate which format matters:
9 CodeWarrior can generate Mach-O or PEF files.
9 Project Builder can generate only Mach-O files.
9 MPW can generate only PEF files.
Depending on the project you are working on, your choice of
development environment may already be made for you.
Because Carbon applications run directly in Mac OS X, they
can take advantage of a number of the new features of the op-
erating system including
9 Protected memory
9 Preemptive multitasking
9 Virtual memory
9 Aqua
From a user's point of view, of course, the biggest advantage
is Aqua.
You can use Carbon not only to take advantage of new Mac
OS X features, but also to help port older applications to Mac
OS X. Some APIs are not available in Carbon; porting an ap-
plication to Carbon will force you to get rid of extraneous or
old-fashioned code.
Printing has been redesigned on Mac OS X, and
there are new calls for printing. If you are using a framework
such as MacApp or PowerPlant, you may not even notice this
change. That's because you do not call the methods that have
changed.
There is still legacy code around that calls nonex-
istent functions from the long-gone Motorola 68K architec-
ture. No longer is this harmless; it will not compile with the
Carbon libraries.
Hardware Access Direct access to hardware is gone for the
most part on Mac OS X. All such access needs to go through
Darwin. Code that accesses hardware directly will not com-
pile (usually in disk drivers or in games that draw directly to
the screen buffer).
Trap Table Trap patching is gone. This was a very elegant
architectural touch in the original Motorola chip. If you had to
call a low-level subroutine, you jumped to a specific ad-
d r e s s ~ a n d the processor then jumped again to a memory lo-
cation that was the value of the address. This intermediate
address was called a trap. You could patch the trap. When
you or anyone else called that trap, the patched code was ex-
ecuted.
Over a period of years, people stopped having much idea
what would happen when they called a trap. It might be
patched or not, and if patched, who knew what that code did?
The Mac OS X structure is quite different. Just about every-
thing is an application. The Darwin core is as small as possi-
ble, and the pieces of the operating system (the Finder, Classic
environment, Dock, communications, and the like) run as in-
dividual processes. (You can see them with Process Viewer.)
Because of this fundamental architectural change, programs
that were control panels or extensions or that relied on them
must be rewritten to run under Carbon.
Code that has been converted to Carbon is generally of better
quality than the pre-Carbon version. First, rewritten code of-
ten benefits from past mistakes and from improved program-
mers' skills. Second, Carbon does not allow you to do some of
the things that are not part of good contemporary program-
ming practices.
Perhaps the most important change to your code is the use of
opaque data structures and accessors in Carbon. The data
structures of the original Macintosh toolbox were available to
anyone. Now, you must access them through accessors, and
you have Apple's commitment that even though the underly-
ing data structures most likely will change, the accessors will
continue to w o r k .
One such change is in process now. Much of the h u m a n inter-
face code is not reentrant which means that it cannot be called
from two different threads at the same time. This c o d e ~ a n d
there is a great deal of i t ~ i s gradually being changed to make
it thread-safe. When this m a m m o t h project is completed, the
h u m a n interface methods will run much faster, particularly
on multiprocessor computers. If you use accessors, you will
take advantage of these changes whenever they occur.
If you have existing code to port to Mac OS X, you can move
gradually from Classic to Carbon as you have the time. You
can adopt minimal Carbonization, then add new Carbon fea-
tures, and finally move to Cocoa. It is not unreasonable to
plan for this to occur over a period of many years.
The investment people have in legacy code is enormous. It
cannot just be thrown out and rewritten (and redocumented
and retested). As perhaps the biggest single developer of
Macintosh code, Apple is well aware of this.
If you are considering converting code, first take an inventory
of what you have. Here are some points to consider:
9 Do you have the source code?
9 Do you have all of the source code (critical files have a
tendency to get lost)?
Can you compile with the current best interfaces from
Apple? The Universal Interfaces from Apple are avail-
able on http'//developer.apple.com. Get the latest
version and check that you can compile.
Can you compile with the current development envi-
ronments? Many legacy programs require legacy
compilers.
Recompile your code with the latest Universal Headers and
the latest version of your preferred development environ-
ment. Then test it. It cannot be stressed enough that you must
make certain that the entire compile-build-run process works
successfully before you start making modifications.
Once you have a successful build, download the latest Carbon
libraries from http" / / developer.apple.com/macosx/carbon/
index.html and start to work.
This section provides a roadmap to the Carbon frameworks.
While CarbonLib runs as a shared library on Mac OS 8.1 and
later, it runs as a framework on Mac OS X, and that distinction
is not noted further in this section.
Apple has approached Carbon from two directions. In the
first, the company has looked at all of the toolbox calls for Mac
OS 9 and decided which to convert to Carbon and which not
to convert. The vast majority of toolbox calls have been con-
verted. Where they have not, Apple's documentation general-
ly cites a reason. For example, Apple events---even on Mac OS
9 ~ p r o v i d e a higher-level and more sophisticated way of
communicating between programs than the PPC (program-
to-program communications) toolbox. Added to the fact that
the PPC toolbox was closely tied to the Mac OS 9 (and earlier)
architecture, this meant that Apple saw little reason to convert
the PPC toolbox. In as many cases as possible, Apple provides
this sort of information: Toolbox calls are not just marked
"unsupported" but a reason and a replacement are provided.
(Note that in the case of libraries or sets of calls, the
workarounds and replacements may be provided at the top of
a file rather than repeated for each individual call.)
The second approach to Carbon has been to look at the fea-
tures provided in Mac OS X and not in Mac OS 9 and provide
as much access to as many of them as possible through Car-
bon. The combination of these two efforts is producing a so-
phisticated set of frameworks on which developers can build
applications for some time. The no longer supported toolbox
calls for the most part were replaced many years ago, but they
were left in place. Now, it is time to clean up legacy code.
While Carbon on Mac OS X consists of frameworks, it is not
the sort of application development framework that Cocoa,
MacApp, or PowerPlant is. In the latter frameworks, you fo-
cus on fairly high-level programming, leaving human inter-
face and basic functionality to the framework. With the lower-
level Carbon frameworks, you are responsible for more of the
programming.
In Cocoa, for example, it is easy to create a descendant of NS-
Document; if you set the appropriate parameters, Cocoa will
take care of saving the document (according to the format you
specify), reading it (again, using your format), and displaying
"Do you want to save" sheets and other interface elements.
On Carbon, you display the sheets, take care of the reading
and writing, and otherwise do programming that is more pro-
cedural than object-oriented. This may be more comfortable
for you; it also may fit in with code that you have already been
working on. Eventually all aspects of Mac OS X will be equal-
ly available from Carbon and Cocoa, so you can choose
whichever environment is more convenient.
In Cocoa, there are 19 major sets of objects; they are grouped
into 9 AppKit and 10 Foundation sets. In Cocoa, there are 29
frameworks grouped into three sets:
0 Carbon frameworks. These frameworks provide most
of the mid-level Carbon support: CarbonSound, Com-
monPanels, HIToolbox, HTMLRendering, Print, Help,
NavigationServices, SpeechRecognition, OpenScript-
ing, IBCarbonRuntime, ImageCapture, NSL, Security-
HI, and URLAccess.
Q Application services. These provide high-level sup-
port, including user interaction: Apple events, ATS,
ColorSync, CoreGraphics, FindByContent, LangAnal-
ysis, LaunchServices, PrintCore, QuickDraw, and
SpeechSynthesis.
0 Core services. These are the lowest-level routines for
Carbon: CarbonCore, NSLCore, OSServices, OT, and
SecurityCore.
This section provides a brief description of each framework. It
should provide you with an overall roadmap so that if you
want to program a specific part of Mac OS X~ColorSync, for
example~you should be able to find the name of the frame-
work in which that support code is listed. Given the frame-
work name, you can search for it in Apple's online
documentation (on the Web or installed from the Developer
CD).
Most Sound Manager calls from version 3.3
are supported. Earlier calls are not, but QuickTime frequently
can replace their functionality.
ColorSync and the Color Picker are located
here, along with their support routines.
HIToolbox This framework contains the basic human inter-
face elements: dialogs, windows, lists, and the like. Most of
the interface is located here. The old Standard File manager is
not supported; it is replaced by NavigationServices. (Apple
has been requesting developers to make this transition for
years.) Also gone is support for editions~an approach to dy-
namic documents that was elegant and sophisticated but was
rarely touched by users and not very frequently implemented
by developers.
HTMLRendering This framework lets you draw in a window
based on HTML descriptions of what is to be drawn. It in-
cludes the data loading functions to retrieve data.
Here is the support for Apple Help, which is described
later in this book in Chapter 14.
These are the calls to create windows and
menus from Interface Builder nibs. (See Chapter 12 for more
about Interface Builder and nibs.)
These are the routines used to identify still
cameras and devices and to download images from them.
NSL The Network Services Location manager provides sup-
port for locating network services available for a computer. Its
primary method is which brings up
the dialog you see in the Finder's Connect to Server command
in the Go menu. This may be the only NSL method you need
to call, as it handles all intermediate processing. When it re-
turns, the value of the last parameter is
the URL of the selected service~or a null string if nothing
was selected.
NavigationServices handles the standard
open and save dialogs that allow users to navigate through
the directory structure (on their own computer or on a net-
work) and through recent and favorite folders. It replaced the
Standard File Package some time ago; Standard File is no
longer supported on Carbon in Mac OS X.
Open Scripting Architecture (OSA) is the Ap-
ple event mechanism that supports AppleScript and other
scripting languages. It contains the routines necessary to
parse object descriptions, to identify properties, to handle re-
cording, and to process events.
Print The Carbon Printing Manager replaces the Classic
printing mechanism, and if you are converting an application,
you may have some work to do. Fortunately, it is not burden-
some in most cases. The Printing.h header file from Classic is
no longer available (nor are its routines). In its place, you use
the headers in the Print frameworks~PMApplication.h, PM-
PrinterBrowsers.h, and Print.h. Each of the Classic printing
calls generally has a corresponding call in the new Print
framework.
If you are using MacApp, you probably never called Classic
print manager routines anyway, so these changes do not af-
fect y o u ~ t h e y have already been done in the conversion of
MacApp.
This framework provides access to the Keychain
Manager. You can use it to let users update their keychains
with passwords from within your application. In addition,
you can use it to retrieve passwords from a keychain so that
users do not have to reenter them in your application.
The built-in speech recognition API is
supported in this framework.
The URL Access Manager lets you send and
receive data to and from a URL using FTP, HTTP, or HTTPS.
Local files ( f i l e ' / / / ) are supported, as are proxy servers, com-
pression, and extraction from Stuffit archives.
AE This library supports Apple event scripting. It is the
higher level set of APIs than the Open Scripting Architecture
framework in the Carbon frameworks.
Apple Type Services provides support for Unicode and
other text.
These are the support routines for color match-
These are the routines that let you access
Quartz for low-level drawing.
This is the support for Sherlock searching;
you can implement it in your own applications for high-speed
data retrieval.
This provides morphological analysis, and it is
currently available only for Japanese.
Launch Services are used to find the applica-
tion to open an application and otherwise find out that type of
information about files and URLs.
These are the higher-level routines to support the
Print framework in the Carbon frameworks section.
These are the two-dimensional drawing routines
that support QuickDraw on Carbon (that is, they implement
QuickDraw calls by using Quartz).
These routines generate speech from your
application.
These frameworks provide the low-level support for Carbon.
CarbonCore The bulk of the Carbon implementation is here.
You will find everything from date and time utilities to the
Alias manager in this framework. If you need a utility and
don't find it in another framework, here is the place to look.
This is the low-level support for network services
location (the Connect To dialog).
Operating system services include power and
disk partitioning.
OT Open Transport provides communications architecture
support at the transport level of the OSI architecture. If you
are writing application programs, you usually do not need
this.
These are the low-level routines that interact
with the h u m a n interface security routines (including the
Keychain Manager) from the Carbon frameworks.
You do not need to adopt Carbon events w h e n you Carbonize
your application. However, doing so makes your application
run a little faster--and it makes other applications on the
same computer run much faster. The Carbon event model
(which is similar to the Cocoa event model) allows for direct
dispatching of events to the object in an application that needs
the event.
Before Carbon events, each application ran its o w n event
loop. Somewhere within the outer block of an application (ei-
ther an application object or a plain, C- or Pascal-based appli-
cation), a loop like the snippets given in this section can be
found.
A whi 1 e loop is at the core of the responsiveness of all user-
driven applications. The faster it executes, the faster a user's
keystroke or mouse event will be picked up by the program.
The utmost responsiveness is guaranteed by keeping all ex-
traneous processing out of the event loop.
Unfortunately, extraneous processing means everything oth-
er than what this program is doing. If you are transferring
files in the background, sending email, or doing anything else
on your computer, those tasks compete with a processor that
is heavily loaded with this whi 1 e l o o p ~ w h i c h is itself wait-
ing for a user event.
This problem becomes increasingly acute as more and more
processes run on a computer, and as more and more events
need to be attended to. This simple m o d e l ~ g r a b the proces-
9
sor and keep it waiting until the user deigns to press a key or
move the m o u s e - - i s very inefficient in a shared environment.
from 1996 (version 1.4d16), here is part of D o E v e n t L o o p "
This loop runs over and over, checking for events of interest.
Dispatching of events is done later within this same method.
For mouse clicks, the process consists of stepping through
where the mouse is clicked and what interface element is be-
neath it:
As you can see, the process involves i f statements within i f
statements. This code--often exactly this code--appears in
many non-object-oriented Macintosh programs.
method through, you will find the code that actually handles
events. This code is common to all event loop-driven applica-
tions. In SimpleText (not built to an application framework),
all of the testing was done in-line. In MacApp, the same test-
ing done in SimpleText occurs in MacApp framework meth-
o d s ~ b u t while the code is simpler, the same process is
carried out (Where is the mouse? What lies beneath it?).
While a certain degree of grouping of types of events can be
When you finally get to a specific type of event, you call a
method in your application to handle it. For example, Han-
dleKeyDownEvent in TDispatcher is called to handle all of
the keystrokes. (That method call is underlined.)
Direct dispatching moves all of this processing out of the ap-
plication and into the operating system. It involves a different
structure, but all the pieces of the preceding code architecture
are still present.
One way to think of the difference between the old W a i t -
N e x t E v e n t architecture and direct dispatching is that all of
the testing and sorting that you used to do after you got an
event is now done before it, so that the operating system can
dispatch the event correctly.
When you work with events, you need to be able to describe
them in the abstract and in the concrete: you must be able to
identify a mouse click abstractly, and you need to be able to
get information about a specific mouse click that has hap-
pened. (This is true also of the older event-handling architec-
ture, but direct dispatching with Carbon events uses different
terminology.)
Identifying events relies on a pair of val-
|dentifyin@ ; : v e n t s
ues: an event class and, within that, event kinds. (This is very
similar to the structure of Apple events--in that case, there
are events, and there are kinds within them. Apple events are
not Carbon events, but there can be similarities.)
There are nine classes of events. For each of those classes,
some of the kinds of events in those classes are shown in the
following list along with the defines for the classes:
0 Application events (launching and quitting, bringing
to the foreground or background, another application
starting or terminating) k E v e n t C i a s s A p p i i c a r i o n
Commands (menu items chosen, enabled, or disabled)
Control (checkboxes, buttons, pop-up m e n u s - -
clicked, created, or destroyed) k R v e n t C l a s s C o n -
Keyboard (key d o w n / u p , modifier key pressed)
Menu (mouse d o w n in menu, m e n u h i d d e n / d i s -
played, menu item enabled/disabled) k E v e n t -
0 Mouse (mouse d o w n / u p , mouse move, mouse move
with button down) k E v e n t C l a s s M o u s e
0 Tablet (touch, pen enters/leaves) kEventClassTab-
let
Text input (character typed, selected text, update text)
Window (created/destroyed, activated/deactivated,
made visible/invisible, content region: cursor moved
in or mouse click in, moved, resized, minimized, to be
moved, to be resized, to be minimized) k E v e n t -
You normally use the defines for classes and kinds. To
uniquely identify an event, you need both, and the E v e n t -
TymeSmec struct declared in CarbonEvents.h combines both
of them.
In the older architecture,
you could examine data within events that your application
obtained from W a i t N e x t E v e n r In Carbon, you cannot ex-
amine the data structures within events; instead, you use ac-
cessor methods to get the data you are interested in. (This is
better p r o g r a m m i n g practice, and in general this sort of cod-
ing style makes issues such as reentrancy and thread safety
much less troubling than is the case when people access inter-
nal data structures.)
Following are the accessors for Carbon events. The first four
take a single p a r a m e t e r ~ a n d EventRef, which is a reference
to an event (it is what you receive when Carbon dispatches an
event to you).
1. G e t E v e n t C l a s s (returns the event class identifier).
2. G e t E v e n t K i n d (returns the event kind identifier).
Q GetEventTime (the time as a floating point num-
b e r - - E v e n t T i m e - - w h e n the event occured).
Everything else about
an event is accessed through
GetEventParameter. While this may look daunting, in
practice, it is very simple to use.
You will find constants in CarbonEvents.h that identify event
parameters for each event. Comments are all in the same for-
mat:
From this, you should understand that the kEventCommand-
P r o c e s s kind of the command event class has two parame-
ters:
To extract the c o m m a n d from a c o m m a n d process kind of
c o m m a n d class event, declare an H I C o m m a n d and then call
You will then be able to access the fields in cmd. (You will see
code to do this later in this chapter in " P r o g r a m m i n g the
Event Handler" on page 165.)
To reference an optional field such as k E v e n t P a r a m K e y M o d -
i f i e r s , you need to check the OSStatus return value as fol-
lows:
The reason for this is that the parameter is optional, and
Ge t E v e n t Parame t e r might not return anything.
is perhaps the most frequently used
method in handling Carbon events. Although it has seven pa-
rameters, you normally care only about two: the event you
pass in (which you receive from Carbon), and the value you
want out (the last parameter). In between, you use the con-
stant and type from CarbonEvents.h, and you specify the size
of the item to be returned.
Here are the steps involved in
setting up direct dispatching:
1. Identify the event targets. (This is a design and plan-
ning step; you don't write code as part of it.)
@ Define the events that you will handle. (These are the
conditions of the swi t ch or i f statements that you
used to test the incoming event in the old architec-
ture.)
@ Program the code to handle those events. (This is the
code that was executed in the body of the swi t ch or
i f statements.)
4. Install the event handler (step 2) in your application.
@ Run the application event loop to let the operating sys-
tem receive events and dispatch them to the handler
you wrote in step 2.
Direct dispatching of events in-
volves the concept of an event target. (You may prefer to think
of a target as the context of an e v e n t ~ t h a t is a less common
terminology, but it may help you to understand the concept.).
In either case, the issue is simple: An event (such as a mouse
click) is paired with a particular action performed by the
event handler (such as closing a w i n d o w ) in the context of a
particular object, or w h e n that object is the target.
Put another way, a mouse click in a w i n d o w ' s close box has a
different meaning than a mouse click on an OK button in a
Save dialog, and that in turn has a different meaning than a
mouse click on an OK button in a w a r n i n g dialog.
In old-style event processing (such as the code snippets given
earlier in this chapter), all events were received by the main
event loop in the application, and they were dispatched by
that code to the appropriate routines to handle the events.
This dispatching of incoming events involves the nested i f
statements or swi t ch statements that you saw in the previ-
ous code snippets.
Event targets in Carbon can be the application itself, win-
dows, menus, or controls (such as buttons, checkboxes, and
the like). If you identify a very specific target, you can avoid
m u c h of the testing to see h o w an event should be handled. In
some cases, no testing is required because a given target han-
dles a given event in only one way. For example, an OK but-
ton is a control, and it can be a target. If you identify it as such,
then an incoming mouse click event can be dispatched with-
out further ado to a routine that does w h a t e v e r a click on the
OK button should do. You do not have to test further.
In practice, w i n d o w s are often the best targets for events in
the user interface. Making each control a target carries things
to extremes.
A target m u s t be able to distinguish between the events that it
receives. If it receives mouse clicks, for example, it needs a
mechanism to k n o w which mouse click occurred in an OK
button and which occurred in a Cancel button.
One c o m m o n case is distinguishing a m o n g control elements
such as buttons. W h e n you create such controls in Interface
Builder, you can assign a four-character code to each one.
Events that are received by a w i n d o w have access to these
codes, and you can easily construct a s w i t c h statement that
lets you route events appropriately. You do not have to test
where the mouse was clicked to find out what interface ele-
ment was clicked on; you will receive that information direct-
ly from the event parameters.
The w a y you do that is to check the r value of the
command that is in the event. The code shown previously gets
that command:
Access the c o m m a n d I D of the control that sent the event by
You are responsible for defining and
you must assign the same value to the control in Interface
Builder.
When you are deciding what to use as event targets, look for
a middle road between no differentiation (that is, sending all
events to the application) and no consolidation at all (sending
events to specific buttons). As noted previously, the w i n d o w
will be the most likely target.
Then, as a reality check, make certain that you will be able to
distinguish among the events your target receives. Look in
CarbonEvents.h to see what parameters will be a v a i l a b l e ~
you will use them (along with the event class and kind) to dif-
ferentiate events. If you cannot differentiate between events
based on this information, you m u s t split them into two or
more targets, in each of which the events are u n a m b i g u o u s , or
you m u s t provide additional information in your application
for the disambiguation. (For example, if you are handling
mouse clicks in objects that m o v e ~ a s in a game or d r a w i n g
p r o g r a m ~ y o u will need to make certain that you are storing
the current locations of those objects so that you can use them
with the mouse location information that is part of the events
you receive.)
};
This information will be used w h e n you install an event han-
dler. If you will be installing two event handlers, you will
need two arrays: one for each of the sets of events that each
handler will be responsible for. Whether you use one or more
event handlers d e p e n d s on h o w you p r o g r a m them. The next
section shows you h o w to do that.
w i n d o w event handler from SimplerText is partially s h o w n in
this section.
As a general rule, a swi t ch statement separates the incoming
event based on its class; within those separations, different
event kinds are handled. (Note that the event kind is located
in the call to G e t E v e n t K i n d before G e t E v e n t C l a s s only to
simplify the code.)
D r a w C o n t e n t , the application's T X N D r a w method is called (it
is underlined). Later on, in response to k E v e n t C l a s s C o m -
mand and k E v e n t P r o c e s s C o m m a n d , the application's P r o -
cessCommand method is called. While your methods m a y
vary, you will probably have an event handler that looks very
much like this.
N o w you can see the significance of having one or more ar-
rays of event definitions. You either separate the incoming
events as shown h e r e - - i n s w i t c h and c a s e statements--or
you separate them in advance by installing separate event
handlers. If you installed all k E v e n t C l a s s W i n d o w events
into one handler, and all k E v e n t C l a s s C o m m a n d events into
another, you would not need the outer s w i t c h statement in
this code. Do what makes sense and what makes the code
cleaner.
The event handler must have three parameters and return an
OSStatus. The prototype is as follows:
You can install a two-stage event handler in which the proto-
type is little more than a shell that calls a more customized
handler such as the one that follows (not that u s e r D a t a is
missing). This two-stage process is described in the following
section.
The existence of the P r o c e s s C o m m a n d is a matter of judg-
ment and style (just as is the choice of h o w m a n y handlers to
install). In SimplerText, P r o c e s s C o m m a n d is merely a large
swi t ch statement. It could just as easily be programmed in-
line in the handler, but that would make the code less read-
able. Here is the beginning of P r o c e s s C o m m a n d :
which the target responds and having written the event han-
dler, you next need to install that event handler for those
events.
The basic installation process involves calling
0 First, you pass in the target as an E v e n t T a r g e t R e f. It
is a window, the application, and so forth.
Q The handler itself is passed in as a universal procedure
pointer (UPP) created with the N e w E v e n t H a n d l e r -
UP P function. It needs to be packaged as a UPP so that
a reference to it can be stored until the callback is need-
ed. If that callback needs to cross the b o u n d a r y be-
tween Mach-O and CFM (for example, w h e n a Carbon
application is a CFM app), this step is essential.
0 You then specify the n u m b e r of events that this han-
dler will respond to.
4. Next, you pass in an array of those events.
0 You can pass in a pointer to any data that you want;
that pointer will be returned to the event handler
whenever it is called.
0 You can also specify an pointer. If
you provide it, it will be created and returned to you
w h e n InstallEventHandler completes. You can use
this pointer to dynamically add and remove events
from the handler as the p r o g r a m executes.
Macros are defined to install event handlers for windows, the
application, menus, or controls. These simplify or eliminate
parameters in the basic procedure call. For example, I n -
The Carbon examples on the Developer CD show you how to
create and install simple event handlers. Here is a slightly
more complex case that you can expand to cover m a n y of the
real-life situations you may encounter. (It is from Simpler-
Text.) It demonstrates the interaction of the u s e r D a t a point-
er and the during event-handling callbacks.
0 Write the handler. This step is the same for all event
handlers and the code always looks something like
this:
2. The actual handler that you install needs to conform to
the prototype with the three arguments mentioned
earlier. Thus, here is the shell prototype that you will
install. Note that all it does is to rearrange the incom-
ing parameters (specifically, casting u s e r D a t a to a
TWindow*) and then call the customized handler from
step 1.
3. To install the event handler from step 2, you need to
package it as a UPP:
4. You need to define the events to be handled:
0 Now, you actually install the event handler (which
will call the secondary event handler) for the specified
events. The u s e r D a t a parameter is passed in as
t h i s ~ t h e object in which this line of code is placed.
It is coerced into a TWindow* object when the handler
is called, and the ttandl e E v e n t method of the object
is called.
Running the Event loop Having identified your targets, de-
fined your events, programmed your event handlers, and
then installed them, you need to start the Carbon event loop
running. Usually you do so in your ma i n function. Here is the
code:
In the Carbon event model, there is much more setup than in
the older architecture using W a i t N e x t E v e n r However, as
you have seen, much of the same code is u s e d ~ i t is just used
in different places. There is less code, though, because the
looping and dispatching are moved into the operating sys-
tem.
Carbon is a framework on Mac OS X (a set of shared libraries
on Mac OS 9 and earlier). You can move existing C++ code rel-
atively easily to Carbon; you also can program new applica-
tions in Carbon, taking advantage of your experience in the
world of C and C++.
Carbon applications take advantage of many of the Mac OS X
features automatically; they can take advantage of others if
you do further programming. In particular, the direct dis-
patching Carbon event model allows your application to run
efficiently (and other applications to run efficiently) in the
shared environment of Mac OS X.
While Carbon at first was thought of as a transitional technol-
ogy, it is here for the long h a u l ~ t h e Finder itself is written in
Carbon, and everything that it can do, both functionally and
in terms of interface, can be done in Carbon.
With two major application development frameworks, Cocoa
and Carbon, Mac OS X provides a variety of choices in terms
of design and programming languages for developers. Com-
pleting the suite of development tools are Core Foundation
and the Apple Class Suites, the topics of the next chapter.
This Page Intentionally Left Blank
There is an enormous amount of C++ code in the world. Much of it
was written for the Macintosh, and still more was written for other
platforms. If you have C++ code, or if you feel most comfortable
writing C++ code, you can do so on Mac OS X. Cocoa is accessible
primarily to Java and Objective-C programmers; Java applications
can also be written for Mac OS X (as Java applications in addition
to Cocoa applications). But C++ remains a workhorse and Apple has
not forgotten C++ programmers. This chapter provides an overview
of three major C and C++ technologies on Mac OS X: Core Founda-
tion, MacApp, and Apple Class Suites.
Core Foundation is a Carbon framework (on Mac OS X--on Mac
OS 9 it is a library) that provides access to the Cocoa Foundation
framework. It can be used to share data among all of the Mac OS X
frameworks and development tools.
About to enter its third decade, MacApp has tracked the develop-
ment of object-oriented frameworks, the Macintosh, and graphical
user interfaces. This section provides a very brief overview of
MacApp, and it shows you how to find out more about it in the most
definitive way possible: by exploring the code in a browser.
Apple Class Suites (ACS) represents a relatively recent project to
pull some of MacApp's functionality out o/the framework and make
it available to people using otherframeworks and even people not us-
ing a framework at all.
Core Foundation provides fairly low-level functionality that
is otherwise provided either by basic language constructs
(such as character arrays--strings), common libraries, and
other tools. They are packaged into reusable programming
entities that incorporate error checking, sensitivity to location
(for strings, dates, and so forth), and the other features that
make the difference between starting from scratch each time
you write a program and building on the powerful accom-
plishments of others (and yourself).
In object-oriented frameworks, some objects~particularly
small ones--have frequently been declared as s t r u e t syntax
elements rather than as true objects. (In Cocoa, this is true of
NSRect, for example. Before the advent of stack-based objects
in MacApp, it was equally common there.) From the pro-
grammer's point of view, there is no difference between using
such object-like s t r u c t elements and using true objects.
However, the use of s r r u e t elements is not satisfactory in all
cases. Core Foundation uses a syntax that lets you work as if
you were in an object-oriented world while not necessarily be-
ing there.
Given an object (my0bj ect), you can invoke one of its meth-
ods (aMethod) in various ways in the object-oriented lan-
guages"
In the Core Foundation syntax, you w o u l d write such a state-
ment as
If parameters were used for aMe t h o d , they would appear in
this way:
This structure is not object-oriented (although its implemen-
tation may or may not be). However, because it is at least ob-
ject-oriented-like, you can refer to Core Framework elements
as objects.
Within the Core Foundation code, macros, and defines, this is
all sorted out so that the right thing happens. Part of the w a y
in which this is done is by hiding everything within the Core
Foundation elements from view. You can get to the contents
only by using accessors such as in the following.
A CFNumberRef object ( v a l u e ) is declared (and created else-
where). You can use an accessor for such an object to retrieve
its value as an integer type and place
it into the int, c u r r e n t V a l u e .
,.~
This is what Core Foundation code looks like: lots of constants
and accessors.
As you can infer from the type names, Core Foundation ob-
jects are references to underlying data structures. As always
when you deal with references, you need to be aware of just
how you are manipulating memory.
First, creating Core Foundation objects is always done with
methods that include "create." These methods take as their
first parameter an allocator that creates the appropriate un-
derlying object and reference to it. Default allocators exist for
all Core Foundation objects, and you use them by passing
NULL as the first parameter. The following code snippet dem-
onstrates the use of a string creation routine. A CFNumber ob-
ject is created with the default allocator (NULL), from a
Next, copying an object needs to use an explicit copy routine;
replacing a reference to one object with another handles only
the references, not the underlying objects. Whenever copying
makes sense, use routines such as the one that retrieves a user
preference for a given application (appName) and given pref-
erence
The allocator that has been used to create a Core Foundation
object is hidden away inside its opaque data structure; w h e n
it needs to be copied, that same allocator is used. In this way,
you can (carefully!) change the actual data elements that are
allocated and used by a Core Foundation object. More to the
point, this is the mechanism by which Cocoa objects~such as
NSString and N S D i c t i o n a r y ~ w i n d up inside Core Founda-
tion objects such as CFString and CFDictionary. (Apple calls
this "toll-free bridging.")
Core Foundation objects use reference counts, which enables
them to be shared among various threads and by several rou-
tines within a single thread. For the most part, if you are writ-
ing a single-user, single-thread application, you can ignore
the reference counts because the default behavior typically is
correct.
Memory management is implemented with reference counts:
Each time a section of code starts to use an object, it incre-
ments the reference count. When you are finished with an ob-
ject, you decrement the reference count. Incrementing the
reference count is done explicitly with C F R e t a i n , it is done
within the processing of all r and CFCreate... rou-
tines. You must balance these calls with calls to r F Re 1 e a s e
w h e n you are finished with an object.
C F R e l e a s e decrements the reference count; w h e n it hits ze-
ro, the framework will delete it. You never explicitly free or
delete an object.
Core Foundation objects are often distinguished between mu-
table versions and immutable versions. This is part of prepa-
ration for thread safety. An immutable object is read-only
once it has been created. In other words, an array cannot be
added to or deleted from, and a dictionary cannot be updated.
Mutable versions of objects need to be locked to make them
thread-safe.
Core Foundation routines are organized into 10 clusters of
services. Each of them is described briefly here. (These are not
Mac OS X services that allow data- and functionality-sharing;
rather, they are services in the common sense of the word.)
Base Services These services consist of basic definitions (true
and false) as well as allocator support and two important util-
ity functions, CFEqual and CFI-Iash. They operate on the un-
derlying data structures within the Core Foundation
references. Always use CFEqual to compare two Core Foun-
dation objects. Whereas the equality operator (==) checks to
see if two Core Foundation object pointer references are the
same, CFRqual checks whether they have the same value or
are otherwise equal but not necessarily the same memory
structure.
Bundle Services These routines provide support for loading
bundles containing resources such as images, sounds, and lo-
calized strings.
Collection Services Arrays, dictionaries, and sets are located
in Collection Services. They are among the highest-powered
Core Foundation constructs. In particular, dictionaries (NS-
Dictionary underneath it all) are used to store preferences and
other unformatted data for an application.
Plug-In Services The code-loading facilities here allow you to
implement plug-in support. If you do not use these routines,
you probably will use Bundle Services to load customized
code modules.
Preference Services One of the most useful services is Prefer-
ences Services. Using dictionaries, it implements preferences
for keys that you specify in your application. It manages mul-
tiple users so that the preferences you store and retrieve are
appropriate to the logged-in user. (An example of the use of
Preferences Services is found later in "Preferences and De-
faults" on page 386.)
These routines convert property lists
to and from XML. Note that property lists require CFNumber
objects; if you happen to have a number you can use Utility
Services to convert it.
String Services One of the largest sets of services supports
strings. String Services handles Unicode and respects the lo-
calization choices for the user and computer. Much of the nas-
ty little character manipulation code you may have written in
the past is written for you in String Services.
These routines let you parse URLs and use
them to load the resources to which they point (CFURGCreate-
DataAndPropertiesFromResource). A significant amount of
Internet interface exists in this set of services.
This is the catch-all location for date and time
manipulation, routines to swap byte orders, and the like.
XML Services converts XML data to data
structures such as trees.
When MacApp became an enormous framework, it was very
difficult to extract small pieces from it for use on small
projects. Apple has started to pull out some of the building
blocks into the Apple Class Suites (ACS).
ACS consists of small, stack-based entities (objects or object-
like objects). You use them as you would any other C type,
and you do not have to worry about creating them with new
or disposing of them when you are finished (although you can
allocate them on the heap if you want).
The elements of the Apple Class Suites provide error check-
ing, and they throw C++ exceptions as you would expect if
problems occur. They mimic and/or wrap Core Foundation
framework objects; using them can help you make the transi-
tion to Cocoa.
They are classified into the following categories:
Interface elements
Arrays, lists, iterators, and maps (These are being
phased out in favor of equivalent C++ standard library con-
tainers.)
Core Memory management, pointers and handles, and ex-
ception handling
Files, streams, resources, and file type handling
Support for help and assistance
Graphics objects such as points, rects, patterns, re-
gions, grafports, and basic text handling
Memory management
Events, properties, and tasks
Media management
Reading and writing data
Parser
Thread management
Debugging
Windows, date and time utilities, resources, menus,
Apple events, and clipboard support
MacApp is widely used both for commercial products and for
in-house projects. (The first version of Photoshop is one of the
MacApp applications along with many other Apple products,
including Apple System Profiler.) It has provided developers
with the ability to present the Macintosh look and feel to users
with a minimum of customized programming. Today,
MacApp is Carbonized, which means that the Aqua interfaces
(and the Carbon event model) are part of your application
with almost no effort on your part.
Moving forward into the future, Cocoa plays a similar role for
projects that are beginning now. Maintenance of existing code
and continuation of ongoing projects frequently require the
use of MacApp.
Three important design considerations influence MacApp:
the Macintosh interface, C++, and multiple inheritance.
In almost all cases, MacApp implements
the standard Macintosh interface. You can create ugly win-
dows and put OK buttons in counter-intuitive locations, but
the default behavior of the interface elements is normally
what a Macintosh user would expect.
While this is not big news to users of frameworks, it is a big
deal to others. When you are working outside a framework,
you may have to implement the functionality of interface ele-
ments and controls; nonstandard behavior can easily creep in.
C++ Although it was originally written in Pascal, MacApp
has been based on C++ for a decade. It uses advanced features
of C++, such as templates and exceptions, as well as many
components from the C++ standard library, such as strings,
vectors, and maps. The use of these features influences the
structure of MacApp.
One of the most important C++ features
that is implemented in MacApp is multiple inheritance.
Whether you approve of multiple inheritance or not (some
people abhor it), a framework design that integrates it as thor-
oughly as does MacApp requires a basic understanding of the
technology.
Classes that are designed to be used in multiple inheritance
are prefixed with "M." The primary MacApp objects descend
from these, but only from two or three of them. For example,
TEventHandler, the superclass of views, windows, docu-
ments, and commands, descends from MDependable_AC
and MStreamable_AC. These are lightweight classes that
manage objects on which others depend and that can be
streamed to or from disk.
Farther down the inheritance tree, TDocument descends both
from TEventHandler and from MScriptableObject (which is
where its AppleScript capabilities come from).
In general, the multiple inheritance classes
can be recognized easily by their "M" and their functionality
can normally be surmised from their names. The bulk of the
framework consists of MacApp classes that begin with "T," a
legacy from the Object Pascal days in which objects were de-
clared as types.
Other classes begin with "C." These are the lightweight Apple
Class Suites objects that are described later in this chapter (see
"Summary" on page 188).
Finding your way through the MacApp class hierarchy is easy
when you have a class browser like that in CodeWarrior. You
need to set a project preference to create a browser. You do so
by choosing YourProjectName Settings from the Edit menu;
in Build Extras, click Activate Browser.
You then open a browser from the Window menu. Figure 9-1
shows a browser for part of MacApp.
If you are trying to track d o w n a class, you can type in the be-
ginning of its name; the browser will scroll to the class. With
a class selected, you can move to its superclass with the left ar-
row on the keyboard. To the right of a class name, you may
find an arrow; clicking on it will expand/contract the sub-
classes of that class (if they exist).
To navigate the multiple inheritance hierarchy, use the small
arrow to the left of the class name as shown in Figure 9-2. If
there is no small arrow, the object does not have multiple an-
cestors. When you select the class you w a n t to examine, the
browser will automatically be repositioned to it.
If you double-click a class, you will open it in its own class
w i n d o w as shown in Figure 9-3. In brief, this w i n d o w pro-
vides you with a list of the class's methods (upper left), its
fields (upper right), and the code for the selected method in
the lower pane. Other controls let you explore the source code
file, add or eliminate elements from the ancestors, and so
forth.
The easiest way to work through the MacApp framework is
just to trace the code (as was done in the previous chapter).
The CodeWarrior class browser is a very efficient and easy
way to do this.
One of the attractions of MacApp is that the entire source code
is available to you. This means you can modify i t ~ i f you want
to. Remember that modifying MacApp source code may well
leave you out on a limb when future versions appear. (There
is a reason that only the first version of Photoshop was written
with MacApp; development of both products diverged at that
point.)
The major classes of MacApp parallel those of C o c o a ~ n o t
surprising, given that they both do much the same thing.
There are some significant differences, however. It is remark-
ably easy to start a battle among programmers about which
architecture is better. In fact, that is among the most trivial of
issues. Your job is to understand the frameworks you work
with and to use them to their best advantage. If studying an-
other framework helps you understand its benefits and avoid
its mistakes, that is less trial-and-error work for you.
Menu Manipulation Although the target chain (MacApp) and
responder chain (Cocoa) are conceptually very similar, Cocoa
takes care of enabling menu commands for you in most basic
cases; in MacApp, you need to do so yourself.
and it does not descend from NSResponder. NSDocu-
ment is primarily concerned with data storage; TDocument
also handles many user events, and it finds itself in the target
chain much of the time. Because a member of the target chain
can set up menu commands, TDocument normally does a lot
more menu manipulation than does NSDocument.
TWindow/NSWindow In MacApp, TWindow is a special
case of TView, and thus it can do anything a view can do (and
more). In Cocoa, NSWindow is a separate object, and it is not
a descendant of TView; it can do less of what TView does.
that can receive events originally sent to their owning
objects. MacApp has two features that show some similarity.
Adorners are small objects that normally do rendering for im-
ages. They can be attached to views, and you can designate
them to be called before or after the drawing of the view. In
this way, you can change the rendering behavior of a view ob-
ject without overriding it.
Behaviors are event-handling objects that can be attached to
any event handler (document, view, and the like). They are
called before the main event handler's code is called. In this
way, they extend event handling without overriding the pri-
mary object.
Delegates provide a somewhat similar mechanism for adding
functionality to objects. They are more general than adorners
and behaviors, but they do address a similar design issue.
Core Foundation provides wrappers for the basic Cocoa
Foundation framework classes for C and C++ programmers
working with Carbon. The wrappers not only allow these
classes to be used, but also allow them to be wrapped with er-
ror checking and other useful benefits.
In a similar way, Apple Class Suites wraps basic language el-
ements of C++ and basic MacApp functionality so that they
can be used independently of one another. Both of these tools
help you be as productive as possible in as short a time as pos-
sible.
Furthermore, MacApp, the original Macintosh application
development framework, allows you to write complex appli-
cations that automatically use the standard user interface.
You may write new applications in MacApp, but more likely
you will modify existing ones to use Carbon (automatically,
with the latest version of MacApp) or Cocoa.
With each of these tools, not only are you able to be more pro-
ductive, but you also can produce more sophisticated applica-
tions that employ advanced error handling and the latest
human interface advances for Mac OS X.
This Page Intentionally Left Blank
This part of the bookfocuses on designing for Mac OS X, using its
development tools, and managing your project. In it, you will find
chapters about the complete product life cycle, from planning the
project, to managing the source code during development, to pack-
aging the resultant application for distribution.
The primary development tools from Apple are Project Builder and
Interface Builder; each gets its own chapter here. There are also
chapters on Apple Help as well as on prototyping and testing.
This Page Intentionally Left Blank
Given the abundance of programming tools and development frame-
works that are a part of Mac OS X, the temptation to jump in and
get started can be great. However, planning a project in advance will
help to assure its success. This chapter provides a brief overview of
some of the most important issues to consider~both in general
terms and in the specific context of Mac OS X.
You can use Interface Builder and the Cocoa framework to develop
sophisticated proof-of-concept demonstrations that will help you,
your users, your managers and funders to understand what it is that
you want to do. Some of those techniques are described in this chap-
ter; references to other parts of the book are also provided to help you
take advantage of these tools.
In particular, Chapter 13, Prototyping and Testing, provides addi-
tional information on some of these techniques. As a very broad rule
of thumb, consider proof-of-concept demonstrations as described in
this chapter to be among the exploratory tools you use to start a
project and to get its initial approval and funding. Prototyping is
what you do during the project as you experiment with different
ways of doing what has already been approved and funded. (Note
that you can use Cocoa and Interface Builder for prototyping any-
thing; you need not use them in your final project.)
Thus, this chapter focuses on what you have to do at the beginning
of a project:
9 Set your objectives.
9 Know your user.
9 Build on the past.
9 Choose your resources.
9 Use Mac OS X features.
You have probably heard all of these instructions before (and will
hear them again), but if your project is to succeed~even if it is a
one-person project that you do on your own time--they are essen-
tial. Fortunately, Mac OS X makes it easy to carry out these steps.
There is one overriding theme to this chapter: Know what is already
there. Even if your project exists only for you to become familiar
with development on Mac OS X, start from existing software prod-
ucts and see what they do and how they do it.
Scores of books and articles have been written about projects
(software and otherwise) that devour years of effort and enor-
mous amounts of money, only to go up in flames. Post-mor-
tems often reveal that either there was no agreement on what
the project was supposed to have done or, if there was, the
scope or scale of the project was unclear.
Many projects have multiple objectives: You may want to
learn something about developing on Mac OS X, learn object-
oriented frameworks, or produce a program to calculate vari-
ous statistics for your work. Make certain that you know what
all of the objectives are and how they relate to one another.
Write down the objectives. A small piece of paper should be
sufficient (if it is not, the objectives are not clear enough).
Keeping the objectives in your head is not a good i d e a ~ y o u
need the concrete words on the back of an envelope or on a
folded piece of paper in your wallet. Be specific.
Next, justify writing your project. Remember that a wide
range of tools exists on Mac OS X. Before you start out, con-
sider using t h e m ~ e i t h e r for the project or for prototypes. In
particular, look at the following:
9 Productivity tools. Can AppleWorks with its spread-
sheet and database documents do what you want?
What about FileMaker or products in the Microsoft
Office suite?
9 AppleScript. Can you add your functionality to a
scriptable application? Doing so will let you write
only your mission-specific code while letting you use
the user interface of the underlying applications.
9 Existing software. Use the various resources on the
software section of Apple's Web site to search for
products that might do some or all of what you need
to do (the URL is http://www.apple.com/software).
Traditionally, the barriers between from-scratch program-
ming (the kind "real" programmers do) and scripting of ap-
plication software has been large. With Mac OS X, Apple is
providing a range of development tools to everyone: Apple-
Script comes in every installation, just as all the developer
tools and compilers do.
If you need to justify your project to management (or to your-
self), having done this research will help you make your argu-
ments. You will be able to hone in on the features that are
necessary to the project that cannot be provided by other re-
sources; in more than one case, a decision has been made that
the cost of special development is not justified for such fea-
tures. In many other cases, though, it is.
Even if productivity tools, AppleScript, and existing software
do not do what you need to have done, they may be useful in
developing working prototypes and proofs of concept. Use
them to put together something that (sort of) looks like and
acts like the program you intend to write.
Many developers are leery of proofs of concept and proto-
types. They have learned from experience that many users see
the prototypes and then wonder why additional months (or
years!) of effort are needed to finish an apparently finished
program.
The objective is to prove that something is feasible. You and
the user should both understand that. Feasibility means many
things in a project. It may mean refining a formula or calcula-
tion that is key to the program. It also may mean proving that
your Mac OS X application can communicate with a corporate
database (that particular proof may require work on both the
Mac OS X side and the database side). Yet another typical
proof of concept is a demonstration so that someone can un-
derstand the process that you are proposing to implement in
your program.
If there is anything tricky about any part of your proposed
project, pull it out and prove it as early as possible. Most of the
biggest fiascoes involve interfaces among disparate systems
and other types of predictable difficulties that could have
been dealt with at the start of a project w h e n time was avail-
able.
Proofs of concept often are bits and pieces of programs. You
may have one little program that proves out your corporate
database connection; another program may prove that your
users can understand the process you are dealing with.
Proofs of concept may fail--but it is better for them to fail than
for an entire project to fail.
Programs written for casual users should differ from those
written for people who sit at a computer all day long. You can
use Interface Builder and Cocoa to quickly come up with
drafts of a user interface that you can use for experimentation.
Avoid deciding how users think and behave in the absence of
research (formal or informal). Customer service representa-
tives who enter data while talking on the phone to clients
have a very different point of view from m a n a g e m e n t and
programmers, for example. Your experiments need not in-
volve your project at all: Ask your potential users which prod-
ucts they like and which ones they do not. Ask them what
annoys them and what makes their lives easier.
Use Particularly if you are a consultant working on a project for a
client, learn the language. Will your software deal with "cli-
ents," "users," "patrons," "prospects," or "customers"? Not
only the interface but the software itself should reflect the do-
main in which it functions. This is all the more critical if ongo-
ing maintenance will be provided by other people.
If you do invent language, make certain that it is clear and
consistent, and that users understand it. Then use that termi-
nology. For new terminology, create a document of defini-
tions, including screen shots and diagrams. You can learn
from Mac OS X itself. A wide variety of newly named inter-
face features are part of its interface~the Dock, toolbars, and
drawers, among them. There is little confusion because their
names are used consistently.
Test the interface with real users. There is more on this later in
this chapter, but for now recognize that usability testing is a
critical part of every project, and you need to plan for it. Also,
the results of good usability testing frequently require repro-
gramming and redesign, so you need to plan for that, too.
More and more, people are coming to understand that these
expensive machines on their desks can do productive work
when their users are off gallivanting around. Make your ap-
plication scriptable (and recordable and attachable) with Ap-
pleScript. Also, consider making it available as a command
line tool. By using the standard CGI interface, you can also
make it available through an HTTP (Web) server. By all
means, do not rule out any of these possibilities; if possible,
include them.
Look at what you have. Most organizations (and individuals)
have a vast amount of preexisting code. Some of it is reusable;
other parts of this code store should be rewritten...someday.
Learn from Apple's example: The Finder in Mac OS X was not
written from scratch. One of the reasons that it is written in
Carbon rather than Cocoa is so that some parts of the Mac OS
9 Finder code could be included in the first releases of Mac OS
X. (Another, far more important, reason was Apple's desire to
demonstrate the long-term viability of Carbon to developers.)
It is always nice to have brand new code with the latest and
greatest features. Unfortunately, brand new code may come
with bugs; it certainly comes with the need to document and
test it thoroughly.
Once you know what you are doing (your objective), w h o you
are doing it for (your user), and what building blocks you can
reuse, it is time to assemble the resources for your project.
The most crucial resource is the people on the project. After
that, you have choices to make with regard to development
environments, frameworks, and languages. Those choices are
intertwined, but they are presented here separately.
For now, Mac OS X is a new experience. Some developers wel-
come these new adventures, while others do not. Given a
choice, it seems obvious (but bears repeating) to select the
people who will enjoy working on a new project. The fact that
you cannot wait to use Mac OS X (or any new development
process) does not mean that everyone shares your view.
Shrink-wrapped versions of Mac OS X ship with Project
Builder and Interface Builder from Apple. They are also avail-
able for downloading from h t t p : / / w w w . a p p l e . c o m / d e v e l -
oper. (You can register at a number of developer levels,
including online and student developers, which incur no
charge.) They both run under Mac OS X and produce Mac OS
X code. For new projects that need to run on Mac OS X, they
are an excellent choice.
For projects that need to be developed to run on Mac OS 9 and
earlier as well as on Mac OS X, you need to be able to generate
code that runs on Mac OS 9. CodeWarrior is an excellent en-
vironment for this.
In the world of Java, both Project Builder and CodeWarrior
provide development environments. In addition, JBuilder
from Borland ( h t t p : / / w w w . b o r l a n d . c o m / j b u i l d e r / ) is an ex-
cellent development tool for Mac OS X.
If you are building on to an existing application that uses
MacApp or PowerPlant, in most cases it is worthwhile con-
tinuing with those frameworks. Both allow you to modify
your code (if necessary) so as to compile Carbon versions.
For new projects, consider Cocoa as a development frame-
work if the code does not need to run on legacy systems. If it
does, MacApp may be the best choice.
You can choose any of the three major languages of Mac OS X:
Objective-C, Java, or C++. The religious wars between Java
and Objective-C partisans are unlikely to abate; however, for
the vast majority of applications, it really does not matter
what language you use. What matters is that the code that is
written is correct and maintainable.
The language choices are related to frameworks and run-time
environments:
9 Objective-C almost always means Cocoa is the frame-
work. Although you can write non-Cocoa Objective-C
code, that is an unusual case.
9 C++ suggests Carbon along with PowerPlant or
MacApp.
9 Java may mean Cocoa with the Java bridge. You also
can use Java to write applications that do not use Co-
coa at all. If you are writing cross-platform Java appli-
cations, this is your best choice.
You can write a Cocoa-based application that looks and feels
like a 20-year-old Cobol application. (It's not easy, but it cer-
tainly can be done.) By the same token you can (with a very
great deal of effort) write an application that sort of looks like
the most sophisticated Mac OS X application using Fortran.
The point is that the tools, frameworks, and languages do not
guarantee what a program looks like or how it runs. They
help you accomplish your goals, and they make it easier to
work within the Mac OS X architecture, but by themselves
they are not enough.
In some ways Mac OS X features are so pervasive that they
may affect everything in your planning process. In other
words, you may get here, think for a few moments, and go
back to the beginning of the chapter. Never fear: Good plan-
ning and development is always an iterative process.
Many Mac OS X features come automatically with the mod-
ern tools: preemptive multitasking, protected memory, and
the like. In two areas, however, you have issues to consider.
These are the user experience and the application structure.
User experience covers the look and feel of the application.
For many people, it is your application. The following items
are the points to consider adopting.
Apple groups them into Good, Better, and Best categories.
That is more or less the order in which they are presented
here.
That order is not arbitrary. The first two items ("Good") are
those items that affect your application when it is not running
(its icons) and, while it is running, other applications. In other
words, the first two items influence the look and feel of the en-
tire computer running Mac OS X~including the operating
system and other applications. Your adoption of Mac OS X
features is critical to being a good citizen.
Cocoa, Carbon, and Java Using these frameworks and tools,
you will automatically take advantage of the Aqua interface
and the internal features of Mac OS X. It is important to note
that while the Classic environment is a critical part of Mac OS
X, it is designed for the transition process so that users' appli-
cations will not break and so that developers will not be
forced to modify their software on Apple's schedule, rather
than on their own.
However, the Classic environment is obviously not the best
way to run an application. All applications within the Classic
environment are linked so that one of them can bring down
the environment and all other Classic applications. It is im-
portant to get out of Classic and into Cocoa, Carbon, or Java
as quickly as possible. [Good]
Your application's icon is visible even when it
is not running. Each application on the computer needs to im-
plement quality icons to make the desktop, Dock, and Finder
look their best. [Good]
System Appearance The Aqua interface comes with Cocoa
and with a Carbonized framework such as MacApp. [Better]
Space the controls in your windows in ac-
cordance with the Aqua interface guidelines. As you will see,
this is very simple in Interface Builder. You can use the guide-
lines that appear automatically when objects are correctly
sized and placed. (See "Designing with Interface Builder" on
page 269.) [Better]
Apple Help Implement HTML-based Apple Help. Having a
standard help system across all of the applications on the
computer makes the user experience substantially better. (See
Chapter 14, Developing Help and Assistance.) [Better]
On Mac OS 9 and earlier, all of an applica-
tion's windows moved forward at the same time in response
to activation or a mouse click. On Mac OS X, you can layer
windows. This makes it easier for users who are working in
two windows that happen to be in two different applications.
(Cocoa takes care of this for you.) [Best]
Help tags provide additional assistance to users
by identifying elements in the interface. Fortunately, Interface
Builder makes adding help tags a very simple matter. [Better]
Sheets and d r a w e r s ~ a s well as tool-
b a r s ~ a r e important new interface elements of Mac OS X. In-
corporate them, but use them properly. Sheets immobilize a
window (rather than an entire application) until they are dis-
missed. Drawers are the perfect place to store information or
controls that are occasionally needed. Toolbars provide cus-
tomizable controls that can appear at the user's command. All
are useful, and all clearly say "Mac OS X." [Best]
Replacing the List Manager in Mac OS 9 and
earlier, the Data Browser (Carbon) and its Cocoa counterparts
(NSOutlineView, NSTableView, and NSBrowser) provide
sortable, movable, and resizable columns. Known informally
as "That ListView Thing," the Data Browser is documented in
Tech. Note 2009~http://developer.apple.com/technotes/
tn/tn2009.html~you can see it in the Finder's Save and Open
dialogs. [Best]
The appearance of your application reflects its underlying
structure to a certain extent. However, there are aspects of its
structure that are apparent to users only as they work with
your application.
Make your application accessible to Apple-
Script. This means making it scriptable, recordable, and con-
nectable. Users can then access its functionality in batch mode
or as part of a complex work flow.
Similarly, consider making some or all
of your application's functionality available from the com-
mand line. When someone is sitting at a computer, the most
expensive part of that picture is the individual: Requiring
someone to press the keys or click the mouse is frequently a
waste of time. The command line interface to Project Builder
is a good example of this. (See "Building from the Command
Line" on page 238.)
Finally, consider making all or part of your applica-
tion a service~or using services provided by others. Users
(and developers) complain of "feature bloat"~applications
that become swamped with more and more features that need
to be programmed, tested, and documented, and which users
have no idea exist.
Write what you need to write, do what you do best, and rely
on the operating system and others to provide the rest.
The basics of planning a project apply to Mac OS X projects as
they do to all others. However, the use of Interface Builder
and Cocoa as rapid prototype development environments can
take a lot of guesswork out of your development.
Having planned your project, it is time to get started. The next
chapter focuses on Project Builder (with some additional com-
ments about the use of CodeWarrior at the end). Then it is on
to Interface Builder and the other steps of actually creating a
Mac OS X project.
This Page Intentionally Left Blank
Project Builder is Apple's integrated development environment
(IDE) that is part of the Developer Tools suite accompanying Mac
OS X. You can use other tools to develop software for Mac OS X.
CodeWarrior from Metrowerks has been a critically important Mac-
intosh development tool for many years, and it remains so in the
world of Mac OS X. It is covered briefly at the end of this chapter.
For Java, JBuilder (as well as CodeWarrior) provides a sophisticated
IDE for development.
Project Builder occupies a special place in the world of Mac OS X
development tools. First, it runs only on Mac OS X (JBuilder and
CodeWarrior run on other platforms, including Mac OS 9 and ear-
lier). In addition, Project Builder is the tool that is used internally
at Apple to build its software~including Mac OS X itself. This
matters because you can rest assured that anything that is done any-
where in Mac OS X or in the scores of applications that are distrib-
uted with it can be compiled using Project Builder.
This chapter provides an overview of Project Builder:
Getting Started with Project Builder introduces you to
the concept of an integrated development environment and
shows you where its components come from.
Using Project Builder is your roadmap to using Project
Builder. The three areas of the IDE (project structure, tools,
and editor) are described.
Building Projects explores targets, build styles, and build
phases. You may never give these a second thought, but if
you are building a large application or working on a project
that involves a number of people, these features can save you
time and confusion.
Building from the Command Line shows you how to use
Project Builder with Terminal and how to construct batch
processes with it.
Working with CodeWarrior provides a very brief look at
the Metrowerks IDE that has played a pivotal role in Mac-
intosh development.
Other chapters provide additional development information:
Chapter 12, "The Tools of Mac OS X: Interface Builder"
starting on page 245 for help with menus, windows, and
other interface elements.
Chapter 15, "Packaging Your Application" starting on
page 311 includes information on packages, nibs, bundles,
and the critical info.plist features.
9 Chapter 16, "Managing Your Code" starting on page 325
includes source code management (SCM) tips for using the
Concurrent Versions System (CVS) built into Project
Builder.
Project Builder is installed in the Developer folder at the root
of your computer. You should see it in the Applications folder
there. If you do not, use Sherlock to search your disk. If that
fails, check your installation disc and Apple's developer Web
site (http://developer.apple.com).
An integrated development environment brings together the
tools you need to edit, compile, link, and debug applications.
Even today, some people prefer to use one tool for editing, an-
other for compiling, and so forth.
IDEs are among the most complex applications in existence,
and their users (developers) are among the most demanding.
As a result, they pose significant user interface challenges to
their designers. Furthermore, m a n y IDE users use the tool for
hours and days on end as they develop applications. As a re-
sult, if you are new to the world of IDEs you may find the in-
terface to any of them daunting; if you are familiar with an
IDE other than Project Builder you may find that it looks dif-
ferent from the one you are used to (every one looks differ-
ent).
This chapter walks you through Project Builder and helps you
to get started using it. If you are not a full-time developer, you
will find m a n y features that you may not need to get started.
In time, you may want to return to this chapter or to the online
assistance to explore some of those features. In any case, do
not take one look and throw up your hands: All IDEs are com-
plex, but they save you time and make you more productive
than you would otherwise be.
Like much of Mac OS X, Project Builder relies on industry-
standard and open-source software. Among its components
are the GNU compiler, the GDB debugger, and CVS. Apple
has integrated these tools with its own editor and other devel-
opment tools; all of them are wrapped in the Project Builder
graphical user interface (as well as in the command line ver-
sion of Project Builder).
GNU Compiler An Apple modification of version 2.7.2 of the
GNU C compiler from the Free Software Foundation I is at the
core of Project Builder. It is used to compile C, C++, Objective-
C, and Objective-C++ code.
If you have Objective-C code, it is most likely compiled with
this compiler. However, if you have C or C++ code that has
been used in the past, it may have been compiled with another
compiler. As always when you switch compilers, take a mo-
ment to review warning (and even error) messages. The GNU
compiler is more stringent than some other compilers in some
cases.
GDB Also from the Free Software Foundation, GDB is a de-
bugger. It allows you to run your program in a controlled
manner, stop it at breakpoints, examine variables, and change
values of variables while the program has stopped.
1. Free Software Foundation, 59 Temple Place - Suite 330, Boston,MA
02111-1307USA, http://www.gnu.org/.
A third major component of Project Builder is CVS--
the Concurrent Versions System is an open-source, network-
transparent, version control system that is used for projects
such as Mozilla (Netscape), KDE and GNOME (graphical in-
terfaces to UNIX and Linux), and the Darwin core of Mac OS
X. For more information, see "Managing Your Code" starting
on page 325.
Project Builder runs on Mac OS X and creates code for Mac OS
X. In that simple sentence you find the answer to the question
of w h e n to use Project Builder.
If you need to create code that will run on Mac OS 9
and earlier without recompilation, you will need an-
other tool to do that. Project Builder handles C, C++,
Objective-C, and Java, but the code that it generates is
in the Mach-O format and therefore can only run on
Mac OS X. (Of course, you can create, edit, and debut
your code in Project Builder and later compile it in an-
other environment to run on Mac OS 9 or earlier.)
If you need to run your IDE on Mac OS 9 or earlier,
you must use another tool.
Finally, note that the p b x b u i 1 d c o m m a n d in Terminal can be
used to run Project Builder's core.You can set up scripts to run
overnight to recompile your projects (this is what Apple does
internally). The c o m m a n d line interface is described later in
this chapter ("Building from the C o m m a n d Line" on
page 238).
Like most IDEs, version 1.0.1 of Project Builder provides a sin-
gle w i n d o w with access to all of its tools. The w i n d o w is resiz-
able, and its component panes can be resized, too. The basic
Project Builder w i n d o w is complex, but if you take a m o m e n t
to look at its components, you will see that it actually consists
of only four basic areas:
1. A customizable toolbar at the top
2. A project structure pane at the left
3. A tool pane at the right
4. An editor pane at the lower right
These are identified on Figure 11-1.
Note that the actual image of the window has been slightly ex-
ploded or torn apart so that the three separate panes are more
clearly visible; also, they are outlined in the figure. The black
rectangles surrounding the three panes do not appear in the
actual window.
The panes are all resizable. You can expand the project struc-
ture pane horizontally. You can also resize the tool pane ver-
tically; doing so automatically resizes the editor pane so that
together the tool and editor panes take up the entire right side
of the Project Builder window. The window itself can also be
resized.
The project structure and tool panes have tabs along their
edges; these tabs change the contents of their views. The edi-
tor pane contains controls along its top. All of these are de-
scribed in the sections that follow.
At the left, the project structure pane shows you the elements
of the project. Four tabs let you examine these elements:
0 Files lets you see the project's files in a logical group-
ing that is independent of those files' locations on
disk.
@ Bookmarks lets you bookmark lines of code in your
project files so that you can quickly return to them.
@ Targets lets you specify what will be built; Project
Builder allows you to declare multiple targets so that
you can build your files in m a n y different ways.
Q Breakpoints are used in debugging; they are the loca-
tions in your code where execution will stop and allow
you to examine or set variables.
The Files tab lets you examine the files and groups of
your projects as shown in Figure 11-2. This is a logical struc-
ture of your project's files; they may exist on disk in this struc-
ture, but they also may exist in a wildly different structure.
Rearrange files by dragging them up and d o w n in the file list.
Create new groups by selecting several files (use command-
click if they are not contiguous in the list) and then choosing
Group from the Project menu. Alternatively, create a new
group from that menu, name it, and drag files into it.
You can drag files or folders into the files view of the project
status pane from a Finder window. You can also use the A d d
Files or A d d Frameworks command in the Project menu to
add them. When you add a file, the sheet shown in Figure 11-
3 will ask you to specify how its inclusion should be handled.
Because files in your project can exist anywhere on your disk,
Project Builder needs to know whether inclusion in the project
should entail copying the file to the project directory. In addi-
tion, the reference style pop-up lets you specify whether the
file's path should be treated absolutely or relative to the
project. For imported folders, you can choose to have them
handled as a group or not. Finally, you can select in w h i c h ~
if a n y ~ o f the project's targets the file should be included. If
this is daunting, rest assured that for most cases, simply leav-
ing the defaults and clicking Add will do the trick. You may
get in trouble if you subsequently move or rename files, but if
you do not, you should be okay.
You can use the disclosure triangles to view files within
groups. If you click a file, it is editable in the editor pane as
shown in Figure 11-4. If you double-click the file, it will be
opened in its own editing w i n d o w inside Project Builder;
CONTROL-double-click will open the file in its preferred appli-
cation rather than in Project Builder. (RTF files, for example,
will be opened in TextEditor.)
The column with a target icon at the top (just to the left of the
Groups & Files title) indicates which files are part of the cur-
rent target. To add a file to the current target, click next to its
name; to remove it, click the small circle again.
If you are running source code management using CVS, a col-
u m n at the left of the Groups & Files view will show CVS sta-
tus. You can see such a column at the far left of Figure 11-3; it
is not present in 11-4.
Sometimes you will see a file name in red, which indicates
that it cannot be found on disk. This may be an error; howev-
er, in the case of the files in the Products folder, it is not. Prod-
ucts contains all of the output of your Project Builder project
(your application, for example). At the beginning, it is listed
in red inside the Products folder; after a successful build, it is
in b l a c k - - a n d it is located on disk.
The second tab from the top of the project struc-
ture pane lets you bookmark sections of your code for quick
reference. You simply select the text you want to bookmark
and then choose Add to Bookmarks (COMMAND-OPTION-
DOWNARROW)from the Navigation menu. Click a bookmark
to go to it in the editor pane; double click it to open it in its
own window as shown in Figure 11-5. Remove bookmarks by
selecting them, then choosing Delete from the Edit menu.
Use the third tab to organize your project's targets.
A target is what you are building. It can be an application, or
it can be a collection of precompiled headers that need to be
compiled and then built into a project. By organizing your
files and targets properly, you can set up complex dependen-
cies. See the Project Builder examples and documentation for
more information on how to create such dependencies. Targets
themselves are discussed later in this chapter (see "Using Tar-
gets" on page 237).
Breakpoints The fourth tab on the project structure pane lets
you manage the breakpoints that you use in debugging.
Although the views within the project structure pane handle
different aspects of your project, all four of them are structur-
al. Files (and groups of files), bookmarks, targets, and break-
points all are part of the structure and organization of your
project.
The editor pane contains the code for the currently selected
file in the Files tab of the project structure pane. A variety of
tools at the top of the editor pane help you maneuver through
the project. Three of those tools involve pop-up menus; they
are shown in Figure 11-6.
The first pop-up lets you quickly select from the editable files
in the project. Note that this pop-up presents the files alpha-
betically; the Groups & Files view in the Files tab of the project
structure pane provides a structured view of the files.
Next, a pop-up lets you see the functions or methods within
the current file. Selecting any one of the items will immediate-
ly bring you to the code in question. (The project must be in-
dexed to do this.)
Finally, a pop-up at the right (identified as the counterpart
icon) provides quick access to header files referenced within
the file you are editing~either explicitly or implicitly by your
use of items declared in the header files.
The combination of these pop-up menus lets you quickly ma-
neuver through your project as you are tracking d o w n code.
But there are even more controls in the editor pane; they are
shown clearly in Figure 11-7.
At the left, the pair of horizontal arrows function just like a
Web browser's back/forward buttons: They take you to the
previous (or next) file that you were viewing in that window.
They are very useful in conjunction with the pop-up menus
that take you to other files.
At the right, the check mark icon lets you compile the one file
in the window to check its syntax. The next icon lets you
switch between header (.h) and implementation (.m) files. The
two rightmost icons split the window into two panes (as
shown in Figure 11-6) or combine panes (as shown in Figure
11-7).
The tool pane is at the upper right of the Project Builder win-
dow. It contains four tabs to let you manage four of the basic
tools:
1. Find
2. Build
3. Run
4. Debug
Two forms of Find are available in Project Builder. The
Find menu provides both. The simplest form is the single file
find (COMMAND-F).Use it to find a n d / o r replace text within
the open file. The Find tab on the tool pane provides access to
the Batch Find feature. It is shown in Figure 11-8.
In the tool pane you first specify the string for which you are
searching; click Find to carry out the search. The results are
shown in the tool pane. You can scroll through them and click
any line to view it in context in the editor pane.
You also use the Find tab to do a batch replace across a num-
ber of files. This is a two-step process. First, do a find. Second,
enter the text you want to replace and click the Replace but-
ton.
The Options button opens the Find Options dialog shown in
Figure 11-9. You can customize Batch Find (and save your
customizations).
Organizing a project's files and editing them are well
and good, but the primary goal of Project Builder is to actually
help you build projects. Click the hammer icon at the left of
the toolbar to build your project. The tool pane will display
the Build view; alternatively, you can click the Build tab in the
tool pane to open the view shown in Figure 11-10. Error mes-
sages appear in the tool pane along with warnings and infor-
mational messages. Because Project Builder integrates all of
its tools, you can click error messages in the tool pane and go
to the corresponding line of code in the editor pane.
If you need to remove all compiled files from your project, the
Clean icon (the broom to the right of the hammer icon) will do
SO.
Run The Run tab shows you run time console messages from
the application as shown in Figure 11-11. You actually start to
run the project by using the Run icon, which is the third icon
on the left of the toolbar in the default configuration. While
your program is running, the icon changes to a Stop sign as
shown in Figure 11-11. Clicking it stops the program.
Note that sometimes when you launch your application from
Project Builder, you may not see its interface. Unless it has im-
mediately crashed (see the Run tab of the tool pane for that
cheery news), you can find it in the Dock; click its icon to bring
it forward.
Debug The final tab in the tool pane lets you work with the
debugger that is part of Project Builder. You launch the de-
bugger with the Debug icon in the toolbar (the bug spray). 2
When you launch the debugger, the icon changes to a Stop
sign, and the tool pane switches to the Debug view shown in
Figure 11-12. You can stop the debugger at any time by click-
ing the Stop sign.
The debugging view is complex (as are all debugging views).
At the top, the Console display contains messages that your
program may write out. Two panes within the main part of
the debugging window provide a stack crawl (at the left) and
a list of variables (at the right). In the case of complex struc-
tures, you can click the disclosure triangles to see the constit-
2. Close examination of the Debug icon shows that it uses organic bug
control products and its aerosol components do not affectglobal warm-
ing or the ozone layer.
uent parts. At the right, the current value of each variable is
shown.
If variable names or variable data are not clearly visible, resize
the Project Builder w i n d o w or resize the columns in this view.
You can control where the application stops by setting break-
points. You do this by clicking in the breakpoint well (the col-
u m n at the left of the editor pane). In Figure 11-12, one
breakpoint is set--at the bottom line.
When the debugger reaches a breakpoint, it stops, and the
variables are displayed as they exist at that moment. It is very
common to set a breakpoint at the end of a method or function
(or just before a r e t u r n statement). By doing so, you can
check the values that have been calculated within that func-
tion. An enormous number of bugs are caused by variables
that have not been set p r o p e r l y ~ a n d this technique catches
that.
You can add breakpoints to your project while the debugger
is stopped~just click next to the lines on which you want to
break. You can also temporarily disable breakpoints by click-
ing them.
The Breakpoints tab in the project structure pane lets you
manage breakpoints as shown in Figure 11-13. It shows you
which breakpoints are enabled. You can click a breakpoint
and go to the code; you also can select a breakpoint and delete
it from the project (using the DELETE key). (You can also re-
move breakpoints by dragging them into the main part of the
editor pane, where they will just disappear.)
You start the debugger running with the spray can icon; exe-
cution stops at the first breakpoint. Thereafter, you control ex-
ecution with the five icons at the right of the toolbar:
1. The first one pauses execution.
0 The next one continues the program, which runs until
the next breakpoint.
0 The third icon (step over) continues to the next line of
code, but it does not stop in a called function. In other
words, if the next line of code invokes a method or
function, you will stop after completion of that meth-
od or function.
0 The fourth icon (step into) steps into the next line of
code within a function or method. This is helpful in
tracing problems d o w n through function calls.
~O The fifth icon (step out) runs the application until the
end of a function or method is reached. This is useful.
Using the last three icons can help you avoid setting multiple
breakpoints. Set one where you start to have trouble, then use
these icons to maneuver through the code.
The Project Builder toolbar is configurable. You can move the
debugging icons out of it (or place them somewhere else in
the toolbar). You configure it just as you w o u l d any toolbar:
You can use the Customize Toolbar c o m m a n d in the Window
menu, or you can use the contextual menu as shown in Figure
11-14 (CONTROL-click in the toolbar to bring up this menu).
This is all well and good, but how do you get to a new project?
Project Builder comes with a number of templates from which
you can choose in the New Project c o m m a n d of the File m e n u
as shown in Figure 11-15.
As you can see, a variety of options are available. You can cre-
ate IOKit drivers, frameworks, and other special-purpose
projects. In most cases, you will choose either a Cocoa, Car-
bon, or Java application.
The other choice to make is whether you want a document-
based application. Regardless of whether it is based on Objec-
tive-C or Java, a document-based application comes with an
NSDocument object created for you. It will be opened auto-
matically w h e n the application is launched, and it is linked to
its own window. If your application does not store data on
disk, there is no need to use a document-based application.
Carbon Applications Carbon applications come in two vari-
eties: plain and nib-based. Nib-based applications let you use
Interface Builder to create the interface; others use templates
to create and load their windows, menus, and other resources.
It is worth noting that another type of Carbon application is
widely used: one based on MacApp. If you want to create a
MacApp-based Carbon application, start from the MacApp
framework and create a new project (or modify one of the ex-
amples). You can then edit it in Project Builder.
The third choice you may make is to create
a Java application. This is a pure Java application. If you want
to create a Cocoa application that you write in Java, choose
one of the Cocoa templates.
You can experiment with the other templates
O t h e r Choices
to see what they produce. In each case, it is worthwhile creat-
ing a new project, building it, and attempting to run it just to
see what Project Builder does automatically for y o u ~ a n d
what that type of project is.
After you have selected your project template, you will be
prompted to name it and to select its location.
Project Builder also has templates for files, as shown in Figure
11-16. You open this window by choosing New (not New
Project) from the File menu.
When you start from a template, the targets are set up for you
automatically. As you proceed, you may wish to add targets
and to otherwise modify the project. Use the examples that
ship with Project Builder to examine how targets are set up.
There are two sections of the Targets view. At the top, you can
list all the targets for a project. At the bottom, you can list and
select from build styles (which are described later in this sec-
tion).
Note that the vast majority of projects have only a single tar-
get; it may have multiple styles (such as debugging and de-
ployment). This section provides an overview of features that
you can explore in depth if you need them for large projects.
With a target selected, yu can use the Files & Build Phases tab
in the editor pane as shown in Figure 11-17.
This lets you select headers, source files, and the like for your
target. If you have used a template and added files only
through Project Builder, you may not have to touch this. The
the Add File sheet shown in Figure 11-3 lets you select which
targets a file should be added to---and it completes this infor-
mation for you automatically.
The second tab lets you control build settings as shown in Fig-
ure 11-18. Build settings let you specify what you are building
and what to do with it (whether to install it, for example).
Here is where you can specify the compiler, linker, and de-
bugger that you want to use (if they are not the default ones).
You also can specify search paths for headers, frameworks, li-
braries, and classes.
The third tab lets you set attributes of the product that you are
building~an application, framework, or whatever. (The tab
is appropriately renamed; it is not available for projects in
which it does not make sense.) The first part of application set-
tings is shown in Figure 11-19.
Here is where you specify the application's name and type.
(Many of the application settings options are involved with
handling application and document types.) You also specify
information such as the version in this part of the Targets tab.
As you can see in Figure 11-19, some of the information that
you provide here consists of strings that will be visible to us-
ers in the Finder; when you localize an application, you need
to modify these. These strings and some of the other settings
here can be set manually in the info.plist file for the project.
Figure 11-20 shows more of the application settings. For Co-
coa applications, you need to set the principal class and main
nib file so that the application can be properly launched. If
you are using a subclass of NSApplication (the default tem-
plates do use NSApplication), you must modify this entry. A1-
so, if you change the name of the default nib file, you must
also make a change here.
Figure 11-21 shows further type information for the Finder.
Note that you can click the Expert button at the right (just be-
low the tabs) to use another interface. This lets you enter data
in the property list directly as shown in Figure 11-22.
The Executables tab shown in Figure 11-23 lets you specify in-
formation for Project Builder to use w h e n it executes your ap-
plication--either in its debugger or when you click the Run
icon. (For Java applications, here is where you can choose
which debugger to use.)
As with most of the target settings, you can usually work with
the default values; you need fuss with them only for ad-
vanced cases or when you are trying to integrate other com-
pilers or complex projects into your environment.
Build styles (shown in Figure 11-24) let you use the same tar-
get for debugging, development, or production.
You can select the style you want in the lower part of the tar-
gets view. You also can add a pop-up menu to the toolbar as
shown in Figure 11-24 so that you can quickly switch between
build styles.
The point of build styles, targets, and all of the other choices
described in this section is to enable you to write your code
and then quickly switch among various ways of compiling
and executing it. If you find yourself modifying the code to in-
clude or exclude debugging features, get yourself up to the
Project menu and add a new target, build style, or build
phase.
You create dependencies among targets simply by dragging
one target (the dependent one) onto another target. Project
Builder automatically builds all dependent targets for you.
Two special types of targets are worth noting:
0 Aggregate targets are nothing more than wrappers of
other targets. You can use them for overnight or other
periodic mass builds. Just pile all of your various tar-
gets into an aggregate target, and when you build it,
they will all be rebuilt.
0 Legacy targets are built using the standard make tool.
As you will see in "Creating a Disk Image" starting on
page 317, you can have a very small shell script depen-
dent on a rather large build. If the shell script is re-
sponsible for creating an installation disk image, that
legacy target (and its dependent target) will automat-
ically produce the installation package.
This section has provided a walk-through of some of the fea-
tures in the Targets tab of the project structure pane. Many
more options are available. Remember that Project Builder is
built on standard tools; if you want to set flags or options for
the compiler, you can do so here---and they will be the same
flags or options that you are used to.
You invoke Project Builder from the command line in Termi-
nal by using the p b x b u i 1 d command. Its syntax is very sim-
ilar to that of b u i l d as the following examples show. By
default, this command builds a project in the default directo-
ry. Thus, if you set your directory to that of a Project Builder
project and type p b x b u i 1 d, the project file will be located and
built.
By default, the output will be placed in the tmp directory; you
can change that by setting DTSROOT (for example, to the
root, as in the following)"
Options to install or clean along with the build can also be set:
You also can select a build style, as in the following:
If you are doing an overnight rebuild of everything, you
might build and rebuild debug, deployment, and other devel-
opment style versions of your project.
CodeWarrior from Metrowerks was the first major graphical
IDE for the Macintosh PowerPC. Before CodeWarrior, most
development on the Macintosh was done using Macintosh
Programmer's Workshop (MPW), which combined compil-
ers, linkers, resource editors, and the like in a command line
environment or graphical IDEs from Symantec/Lightspeed.
(Even earlier, the Lisa Workshop, which ran on the Lisa, was
used to develop the original Macintosh software and applica-
tions.)
CodeWarrior's compilers outperformed those in MPW from
the start. The reason for this was that the MPW compilers (as
was the case with all of MPW) were designed to work in the
smallest possible memory configurations. As a result, they
were heavily disk-bound, reading and writing intermediate
results throughout the compilation process. CodeWarrior,
coming along in a later environment with faster processors
and much larger memory configurations, sucked up large
chunks of code and worked on them in memory, spitting out
compiled or linked code in an efficient manner. (The reason
that this is worth noting is that it demonstrates once again
how important it is for memory management to be handled
by the operating system, as it is in Mac OS X, rather than being
implemented in individual applications.)
Today, CodeWarrior runs on Macintosh and Windows com-
puters as well as Linux, Solaris, Java, and other platforms; it
generates code for Mac OS 9 and earlier, Mac OS X, Windows,
and Java. It ships with a sophisticated application develop-
ment framework, PowerPlant, which many people have used
to develop Macintosh applications. From the start, it has been
a critical tool for MacApp development.
CodeWarrior provides many of the same types of features
that Project Builder and all other IDEs provide. CodeWar-
rior's approach involves windows that are less complex than
those of Project Builder. In addition, CodeWarrior defines tar-
gets somewhat differently than does Project Builder.
One way to get started with CodeWarrior is to download the
complete current MacApp, including the Apple Class Suites,
from http://developer.apple.com/tools/macapp. Drag the
downloaded folder to wherever you want it on your disk.
Within the ACS folder, you will find a CodeWarrior support
folder (it may be called CWP7~CodeWarrior Pro 7 ~ o r it
may have some other name). Within the CodeWarrior sup-
port folder, you will find a MacApp folder, and within that,
an Examples folder. From CodeWarrior, you can open any of
the example projects, or you can open one of the Standard Ex-
amples projects that contains all projects. Figure 11-25 shows
the Files tab of one example, Nothing (the smallest MacApp
program).
You can add files to a project by dragging them into the win-
dow; likewise, you can move them around. (All of this is like
Project Builder.)
Targets in CodeWarrior are shown in Figure 11-26. As in
Project Builder, targets can contain subtargets, and the IDE
manages the dependencies. However, unlike in Project Build-
er, targets in CodeWarrior can differ from one another in that
some are for debugging purposes and others are not. (In
Project Builder, this is handled with build styles.)
CodeWarrior provides a host of settings for projects; these set-
tings include whether the code that is output will be for Mac
OS 9 and earlier or for Mac OS X.
If you have a project in CodeWarrior, you can export it and
import it into Project Builder. Use the Export Project com-
mand in the File menu to create an XML representation of the
project.
This chapter has provided a basic overview of Project Builder.
Examples abound both on the Developer CD-ROM and on Ap-
ple's developer Web site; there is additional documentation
on both of those locations.
The easiest w a y to get to know any IDE such as Project Build-
er or CodeWarrior is to use it. One important tip will help you
get the most out of your experimentation: Do not start from
scratch. Take a MacApp example or a Cocoa example and
open it in Project Builder. Build it, and then run it. Explore
what you have done and what the settings are. It is a rare pro-
grammer who really starts from scratch on a project. In most
cases, people take an example that is close to what they want
and work from it; they add features, remove others, and grad-
ually morph the example into their finished product. Apple's
example code contains copyright notices that encourage this
sort of use.
With Project Builder helping you manage your code, you can
turn to Interface Builder to work on your interface. That is the
topic of the next chapter.
This Page Intentionally Left Blank
Interface Builder is the graphical tool that you can use to design
your Cocoa-based interface. It is much more than just a graphical de-
sign tool, however. It helps you create the shells of interface classes
that you will implement in Project Builder; it also reads Project
Builder header files and imports the relevant parts into its own en-
vironment. The Aqua human interface guidelines are implemented
in Interface Builder, too. Guidelines appear dynamically as you
move objects around so that you can position them appropriately.
After a brief overview, the chapter focuses on three major areas of In-
terface Builder as it is used with Cocoa:
9 Using Interface Elements. This section shows you how to
add menus, windows, and views to your interface, and how
to make them work with your application's code.
Designing with Interface Builder. The Aqua guidelines
and dynamic measurement tools are presented here, helping
you to make your interface look as good as possible (and be
as useful as possible).
Programming for Interface Builder. Actions, outlets, re-
sponders, and other programmatic issues are described here.
The concepts are really not that hard to understand, and you
do not have to do much with them, but you do need to know
what they are.
Following these sections, you will find a discussion of using Inter-
face Builder with Carbon.
Apple provides extensive documentation on Interface Builder, in-
cluding step-by-step tutorials. This chapter does not attempt to du-
plicate that documentation, so you may wish to go through one or
more of the tutorials. You can do so before, during, or after the time
you read the chapter. The tutorials tell you what to do, while this
chapter is a bit more oriented toward "why."
Interface Builder is opened automatically when you double-click a
nib file in the Groups & Files view of the project structure pane in
Project Builder. You also can start from Interface Builder to create
the interface for a project that does not yet exist. For most people, it
is easiest to start in Project Builder and create a new project using
one of its templates and then to move into Interface Builder.
Interface Builder edits nib files~the files that contain infor-
mation about each interface element (menus, windows, and
views, for example). This information consists at a m i n i m u m
of the size and location of objects ensuring that they can be
created on the user's display as needed.
The display of objects from a nib file's information is done by
the application program. When it is a Cocoa program, Cocoa
itself handles most of the nib operations automatically. Cocoa
objects in nib files contain far more information than their size
and location. Objects that you declare as descendants of Co-
coa objects (custom views, for example) have their ancestor's
information stored in a nib file, but w h e n you actually load
the nib file your own code is invoked to display the object and
set data values.
It is important to note this point, because it means that custom
views will need programmatic attention in most cases when
they are being placed in a w i n d o w if they contain data other
than standard view information.
Cocoa's views and menus are always stored in nibs; in Car-
bon, they may or may not be. Older Carbon applications do
not use nibs (they were not available). Today, they are avail-
able, and if you are writing a Carbon application from scratch,
you can use Interface Builder to design its interface and to cre-
ate nibs. This makes it easier for you to work in both Carbon
and Cocoa environments because your work will be similar.
Carbon treats nibs differently from the way in which Cocoa
does, but your work is much the same.
Each Cocoa application normally has a main nib file. It is cre-
ated for you automatically from each of the standard tem-
plates. If you change the name of the main nib file, you need
to set the new name in the application settings for the target
(look for the section titled Cocoa-Specific in that pane). It is
much easier not to change the name of the main nib file from
that provided by the Project Builder template.
Your main nib file and its contents are automatically loaded
when the application starts up. This is essential because this
file contains your application's menus, and they must be there
as soon as the file appears on your display.
In addition to the menus, this nib file normally contains any
controllers you may have (as in model-view-controller), at
least the application's main w i n d o w and its views, formatters,
and contextual menus for that main window.
In some ways, nib files are like resource forks in Mac OS 9 and
earlier. Additional nibs can be loaded on demand. This means
that you can load the minimal resources for your application
(menus and main window) and then load the resources that
are relevant to commands that the user issues.
It is common to pair a nib file with a document in your appli-
cation. The document's windows and views are thus inti-
mately connected to it. (Actually, you pair a nib file with a
document class; the document class and the nib file's objects
are instantiated for each document that is created. If you run
the TextEdit example and create several documents you will
see this in action.)
The main nib file for your application is specified in the appli-
cation pane of the target as mentioned previously. If you in-
stantiate an object that has its own nib file, you need to
identify that nib file. In your descendant of the NSDocument
class, for example, override windowNibName as shown here
(assuming that your nib file's name is DiaryDocument):
Java:
Objective-C:
A nib file is opened automatically when your application is
launched; in the NSDocument class, it is opened when a doc-
ument is created. The actual loading of the nib file is done by
a window controller. Documents with one window each have
a default window controller. If your document has multiple
windows, you need to override the window controller so that
it can handle the windows. (An example of this is provided
with Project Builder.)
For NSDocument descendants, the method
thereafter, you can do anything that you want. Some code
from Diary is shown here. (The code in italics is the sort of
code that you add--everything else should be included as is
in your application.)
Java:
Objective-C:
Another hook involved in nib file creation is awakeFrornNib;
it is called for each object that has been created from the nib.
For document-based applications, overriding windowCon-
tro I i erDiflGoadNib is usually best: Everything is created
and is just about to be displayed. Even custom classes require
very little fiddling other than setting their initial values. Be-
fore starting to program adjustments to your nib objects, look
at the examples to see how they are done.
When you open a nib in Interface Builder, you normally see a
window with tabs at the top. The main nib for a Cocoa appli-
cation appears at the top of Figure 12-1. An application with
multiple nibs (such as a document-based application) has two
nibs that you can open as shown at the right of Figure 12-1. (In
Carbon applications, only two tabs appear in nib files: the In-
stances tabs as shown here and the Images tab.)
Three objects appear by default in your nib file:
0 File's Owner. This icon represents the object owning
the nib. For a main nib, it is your application object
(usually an instantiation of NSApplication itself). In
the DiaryDocument nib, File's Owner represents the
owning object~the customized DiaryDocument class
that overrides NSDocument. In either case, File's
Owner is normally set up for you by the Project Build-
er template.
0 First Responder. This is used to dispatch events to ob-
jects throughout your application; it is described later
in this chapter (see "First Responder" starting on
page 277).
0 Font Manager and other objects needed by your appli-
cation may be automatically inserted into the main
nib.
A main nib also has a M a i n M e n u object that contains your ap-
plication's menus. If you double-click it, you open the M e n u
editor s h o w n in Figure 12-2.
You can rename m e n u s by double-clicking their names and
typing n e w names. As you will see in the next section, you can
also add m e n u c o m m a n d s and n e w menus.
You manipulate most of the interface elements in Interface
Builder. You need not do so---you can create your interface el-
ements programmatically, but it is easier to use Interface
Builder.
This section shows you h o w to create interface elements;
" P r o g r a m m i n g for Interface Builder" starting on page 271
shows you h o w to make them active. You deal with three
main interface elements"
9 Menus
9 Windows
9 Views
There are two types of m e n u s in Cocoa applications" m e n u s
that appear in the m e n u bar at the top of the display, and con-
textual menus that appear w h e n you CONTROL-click on an in-
terface element.
A palette of interface elements is available to you; if it is not
visible, choose Palettes from the Palettes s u b m e n u of the
Tools menu. The palettes in Cocoa and Carbon applications
are different; furthermore, you can customize palettes in Co-
coa. As a result, your palette m a y not look like the ones shown
here, but it should be similar. At the top, buttons let you
choose the pane containing the type of interface elements you
want to work with. Click the m e n u button as shown in Figure
12-3.
From here, you can drag prepared menus into the m e n u bar.
Existing menus will move aside for your new menu. Be cer-
tain not to be creative with your placement of menus. The area
with which you can play is between the Edit m e n u and the
W i n d o w menu. The Apple, application, File, and Edit menus
must be the first four menus; the Window and Help menus
must be the last two.
9
You can select any item in the menu and examine its attributes
with the Info w i n d o w from the Tools m e n u ' s Show Info com-
mand, shown in Figure 12-4.
The Info w i n d o w is used to examine and set values for m a n y
Interface Builder objects. Its pop-up menu at the top lets you
switch among a variety of displays, of which Attributes is
only one. The others will be shown throughout this chapter.
The attributes vary for different types of objects. For menu
commands, as you can see here, you can set key equivalents,
initial settings, and a Tag ID.
The Tag ID is available for all palette items; it is passed to you
in events and you can use it to dispatch them in the Carbon
event model.
Now comes the most powerful part of the Interface Builder
mechanism~connecting interface elements to commands
and to one another. Holding down the CONTROL key, you drag
from a menu command to the object that you want to respond
to that command. When you release the mouse button, the
Info window will open to the Connections pane of the object
from which you drew the connection.
Figure 12-5 shows a connection drawn from the Delete Entry
menu command to the First Responder object in the Main-
Menu nib file. In the Info window that is open, you can see
that the Connections pane shown is for an NSMenuItem (this
is in the Info window's title bar).
Sometimes multiple outlets appear in the left side of the upper
part of the window; at least one will. If there are multiple out-
lets, you select the one to which the action will be sent. Here,
there is only one (target), so you move to the right-side list
and select the action (or "method" or "message") of the target
that you want to occur.
To complete the connection, you click the Connect button at
the bottom right. Once the connection has been made (as it has
been in Figure 12-5), the button changes to a Disconnect but-
ton so that you can undo your handiwork.
This process is repeated frequently as you build an interface.
To have an interface element cause an action to occur in an-
other element (for example, to have a menu command cause
a document object to delete an entry), do this:
0 Establish the connection. From the element that will start
the event (the menu command, the button, etc.), CON-
TROL-drag to the object that contains the object that
will receive it (the document, the application, etc.).
First Responder is a special type of object, which is fre-
quently used; it is described later in this chapter.
0 Select the object that will receive the event. In the Info win-
dow, select the object in the receiving object that will
get the event. Sometimes only one possibility ("tar-
get") exists; in other cases, there are multiple choices.
A drawer, for example, will contain a p a r e n t W i n d o w
and a c o n t e n t v i e w ; it also contains a d e l e g a t e .
Even without knowing much about what is going on,
it is usually not hard to guess at what you are dealing
with. Beyond that, the examples and Apple documen-
tation provide full information. Remember that inter-
faces are usually simple; they are complex only in the
variations that users can ring from the basic themes.
An interface that itself is fundamentally complex is
usually unsuccessful.
0 Select the action. From the scrolling list at the right, se-
lect the action that is to occur.
4. Complete the process. Click connect.
Sometimes there is no immediate action to perform, but you
need to connect one interface element to another one. This is
the case in the next section, where you will see a drawer con-
nected to its content view as well as to its parent window. The
process in that case is three steps: Make the connection, select
an object, then click Connect.
If you are not comfortable with the process yet, have no fear:
It is repeated throughout this chapter. In addition, you can
work through the step-by-step Interface Builder examples
and gradually you will find that the process installs itself au-
tomatically in your fingers; you will not have to think about it.
The process of connecting objects described here works for
m e n u commands as well as for windows, views, and controls,
as you will see in the following section.
The w i n d o w s palette is shown in Figure 12-6. Drag a window,
a w i n d o w with a drawer, a panel, or a drawer itself into the
nib w i n d o w to create that object in the nib.
Whenever you create an object from a palette, you set the rel-
evant attributes as shown in Figure 12-7.
Figure 12-8 shows an example of the second type of connec-
tion referred to previously: It establishes a link, but no action
is specified. This is a very common type of connection in In-
terface Builder.
The connection is d r a w n from the w i n d o w ' s title bar to the
File's Owner object in the nib. This means that any event sent
to the w i n d o w will be passed on through this connection if it
is not handled by the window. The d e l e g a t e outlet in the
File's Owner object is the connection to which the w i n d o w is
linked. (These connections are called outlets, but that term
sometimes confuses people because it implies a directionality
that may not always be obvious.)
As you can see in the lower part of the Info w i n d o w ' s Connec-
tions pane, the delegate has been set to the DiaryDocument
object. Thus, an event sent to the w i n d o w (a generic window,
after all) will ultimately be passed on to the DiaryDocument
custom object. In m a n y cases, you have choices among a num-
ber of outlets (as, in fact, you do here).
You can quickly set up relationships among interface ele-
ments. For example, if you have an NSDrawer object in your
nib, you can connect it to a parent w i n d o w as shown in Figure
12-9.
From the NSDrawer object, CONTROL-drag to the w i n d o w ' s
menu bar. In the line shown in Figure 12-9 and other figures
in this chapter, the small rectangle shows the start of the con-
nection.
From the Connections pane in the Info window, set that con-
nection to be to the p a r e n t W i n d o w outlet. This really is not
very difficult; in fact, it is quite obvious as soon as you start
doing it. A n d in this particular case, you can drag a w i n d o w
and its d r a w e r from the palette into your nib file, and the win-
dow, drawer, and content view are all created and connected
for you automatically.
A d r a w e r has no visible information; it contains a content
view into which you place your interface elements. To link a
view to a drawer, forge another connection as s h o w n in Fig-
ure 12-10. From the drawer, CONTROL-drag to the view and set
it as the c o n t e n t v i e w as s h o w n here.
You will note in the Connections pane of Figure 12-10 that two
Views are used within windows to display information and to
provide objects for user actions (controls). The two views pal-
ettes are shown in Figures 12-11 and 12-12.
You drag the type of view you want to use into a w i n d o w and
place it where you want it. As you can see, buttons, sliders,
image wells, and a host of other interface elements are avail-
able. If you are tempted to create your own, consider whether
you really need to do so (the answer is usually no).
Note that you can drag any of these views directly into the nib
file. You place them in a w i n d o w when you are preparing that
w i n d o w for display. However, if you want to create a set of
views that will be programmatically placed into a window,
you can do so. Remember to set the Tag ID so that you can re-
trieve the view hierarchy from the nib and add it to the win-
dow w h e n you are ready to do so.
All of the views allow you to set their size in the Info w i n d o w
as shown in Figure 12-13.
You can experiment with these settings very easily in Inter-
face Builder. Set the size for a view within a w i n d o w (either
here or by sizing it directly) and then test the interface~Test
Interface (COMMAND-R)from the File menu. This works for
most of the Interface Builder changes that you make.
In the view Size pane, you can not only set location sizes, but
also use the spring and struts to indicate if a view should be
placed at a fixed location from its superview (or window)
edges or should spring to relative positions. As you will see as
you click on the springs and struts--the lines from the view to
the b o r d e r ~ t h e y alternate between coiled spring-like objects
that indicate flexibility and struts that indicate fixed dimen-
sions.
As always when you drag an object from a palette into your
nib file, you set its attributes using the Info window. Figure
12-14 shows the attributes for a variety of views. Each view
functions the same way but has different attributes. You can
experiment with each one to see how it works.
The following three views are commonly used for displaying
images and text. Note that they come complete with their own
m e n u commands; the appropriate items in the Edit and other
menus are enabled for each view as necessary.
Image Views You can place an image in an image v i e w ~ o r a
user can do so if it is marked as Editable in the attributes. As
you can see from Figure 12-14, you can control the image's
placement and sizing within the image view.
These are used for brief (usually one line) entries
of text. Use them for a name or address field, for example.
T e x t Views These views can contain large amounts of text.
Memory is the only constraint on their size. You can set at-
tributes to allow Rich text and even the inclusion of graphics.
A text view brings with it all of the standard text editing com-
mands, including Find/Replace and Spelling.
Figure 12-15 shows tabulation views from the palette. These
views allow you to group data together.
One of the most frequently used of these views is the tab view,
shown in Figure 12-16.
You can drag other views and controls into a tab view as
shown in Figure 12-17. To do so, you must select one of the
tabs and double-click so that the edit focus is visible.
In Figure 12-16, the tab view itself is selected; changes that
you make to it affect the entire assemblage of views. In Figure
12-17, the focus ring surrounds the selected tab, and you can
add subviews to the selected tab. (If you do not see the differ-
ence, look at the area around the tab view and just inside the
w i n d o w frame.)
As you move interface elements around in Interface Builder,
guidelines appear as shown in Figure 12-18. These guidelines
suggest where you should place objects and how you should
size them so that they appear as suggested in the Aqua human
interface guidelines. (If the guidelines are not visible, you can
turn them on from the Guides submenu of the Layout menu.)
There are two sets of guides: Aqua guides, which help imple-
ment the interface, and user guides, which you can create to
organize your window's design. Taken together, these guides
contribute enormously to making your interface look consis-
tent not only with itself but also with the Aqua guidelines. It
is worth playing with the guidelines a bit. Move and resize
your interface elements so you can see how the guidelines ap-
pear. Some of their measurements (distances between objects,
for example) are absolute. Others are calculated to make sim-
ilar objects (text fields, for example) of similar sizes. This sec-
ond category of guidelines is ultimately under your control.
In addition to using the guidelines, you can have Interface
Builder measure distances for you. Select an element in a win-
dow; then, holding down the OPTION key, move the mouse
around. Measurements will appear from the selected object to
the object under the mouse as shown in Figure 12-19.
Finally, you can use the Show Layout Rects command from
the Layout menu to see the display shown in Figure 12-20.
This is particularly useful when you are trying to align shad-
owed objects and objects that contain text. It is usually more
pleasing to align baselines of text objects even though the out-
side boundaries of those objects may not be aligned. Layout
rects can help you decide what should go where. (Note that
the guidelines handle this case well; layout rects help you do
additional troubleshooting.)
Everything that you have seen so far in this chapter has in-
volved Interface Builder and the methods of its default objects
(with one exception). Most of your interface will involve these
default objects and their methods. However, the mission-crit-
ical parts of the interface will normally involve custom objects
and the methods that you write in Project Builder.
Use the Classes tab to examine the classes of the objects in
your nib file. That tab is shown in Figure 12-21.
In the two columns at the right, you will see outlets and ac-
tions, with a number next to each one indicating h o w m a n y
there are. Outlets are the connections to objects that have been
described in this chapter (a parentWindow outlet in the NS-
Drawer object, for example). Actions are the methods that are
called w h e n user actions occur (the d e l e t e E n t r y method
was referred to previously).
Objects built for Interface Builder have a variety of outlets and
actions that are visible in the Classes tab of the nib file. With a
class selected, you can add an outlet or action from the Classes
menu. You can name it, and then it will show up in the appro-
priate Connections pane. You can then use the Create File
c o m m a n d in the Classes m e n u to create a header file in your
Project Builder project.
You can also w o r k the other way. That is, you can create files
in Project Builder and use the Import Classes c o m m a n d to
bring them with their outlets and actions into Interface Build-
er.
The step-by-step tutorials walk you through this process.
However, you will soon see that in real life once the initial
skeletal interface is built, you normally need to synchronize
the files manually. This is done so that the code you add to
Project Builder files is not overwritten by Interface Builder.
Actions are listed under the appropriate classes in the Classes
tab; they are implemented in your project files. All action
methods have the same format. Here is a sample action that
was referred to earlier in this chapter:
Java:
Objective-C:
All actions take one parameter. In Objective-C, it is sender
(lowercase) and of type id. In Java, it is Sender and of type Ob-
ject.
The Java action returns void. The type of the Objective-C ac-
tion is null, but the defined constant is used for
clarity and to help Interface Builder in scanning header files.
As you can see from the code, the action methods can do any-
thing you want. They have full access to all of the objects and
variables of the files in which they are located. Sometimes an
action is one line of code; other times it is many lines.
In designing your actions, remember that they will be linked
to interface elements. As a result, they should be simple. In
some cases, a complex action in your code may call several
simpler actions. This allows various interface elements to call
the components of the complex action.
Outlets are the connections that you make from one object to
another--this button in the user interface is connected to the
m y B u t t o n variable in the code, for example. They do not in-
volve a single action (as is the case with a menu command),
but they are linked for the course of the program's execution.
Typically, your outlets include interface elements that you
need to deal with programmatically. For example, here are
the outlets for DiaryDocument (in part):
Java:
Objective-C:
As you can see, in Objective-C, you identify outlets with
IBOutlet. In Java, they are simply private to the object.
It is not necessary to create such outlets. However, if you need
to load or unload data from interface elements, your code
needs to be able to get to the fields of your interface. Thus, you
declare them as outlets. You need to link them up in the inter-
face. You have actually seen how to do this already; here it is
again with further explanation.
CONTROL-drag from an interface element to the object that
contains the outlet you want to connect. In the case of a docu-
ment-based application, the File's Owner object of the docu-
ment nib file is set to the document class (MyDocument, by
default), and the outlets you add to MyDocument are shown
in the Connections pane as you see in Figure 12-22.
The t i t 1 eF i e 1 d outlet was declared in code like that shown
in the previous section. It is connected to the text field in the
w i n d o w in this manner. What is typed into the text field w h e n
the p r o g r a m is running can be accessed by your application
by using the t i t l e F i e l d variable it contains. Likewise, the
application can initialize that field to a given value by setting
the t i t 1 eF i e l d contents programmatically.
In the case of documents, the override of w i n d o w D i d L o a d -
NibF i 1 e is where you do this loading.
The other piece of legerdemain that lies behind this window
is how the outlets get into the File's Owner object. The docu-
ment template sets File's Owner to MyDocument (which it
creates automatically). You may choose to rename that class
(and you should).
You can see that in Figure 12-23. Select File's Owner and look
at the Attributes pane in the Info window. You can change the
File's Owner class to another class if you want to.
The list of classes in the Info window comes from the classes
listed in the Classes tab of your nib window. You can add a
class by using Subclass from the Classes menu. You also can
automatically add a class by choosing Read File from that
same menu (if you have declared the class in the imported
file).
If you add a class with Subclass, whatever class is selected in
the Classes list will be subclassed. If none is selected, the com-
m a n d is not available.
The outlets (and the actions) for your classes appear in the
same ways: either by reading from a file in which they are de-
clared or by choosing the A d d Outlet or A d d Action com-
m a n d for a selected class. The step-by-step tutorials walk you
through this, and you will get used to it very quickly.
Finally, the issue of the First Responder needs to be dealt with.
First Responder is the head of the target chain (in MacApp
terms). It is the object that gets the mouse click or keystroke
first. It changes as the program executes, and you rarely set it.
(Your objects may resign from that role or refuse to ever be-
come a First Responder, but you rarely aggressively grab First
Responder status.)
The First Responder is listed in the Classes list, but it is not an
object in the sense that the others are. Instead, it is whichever
of those objects happens to be the First Responder at a given
moment. You need the First Responder w h e n you need to
send an event to an object that you cannot identify in the nib
window.
An example is the d e l e t e E n t r y action, which was connect-
ed to the menu bar earlier in this chapter. The menu bar is in
the main nib. The d e l e t e E n t r y action is an action of the Di-
aryDocument class; DiaryDocument shows up as File's Own-
er in the secondary nib file. You cannot make a connection
across nib files, so you cannot connect the menu command to
the File's Owner object in the secondary file. (If you could,
you could connect it to the de 1 e t e E n t r y action and be done
with it.)
What you do is add the d e l e t e E n t r y action to the First Re-
sponder "object" in the main nib file. You can make a connec-
tion from the menu c o m m a n d to the First Responder, and you
can choose that action. When this actually occurs, Cocoa will
search the responder chain for the first responder that re-
sponds to d e l e t e E n t r y (i.e., that can process it). It will find
that object in the DiaryDocument object that is in the respond-
er chain. (If you have several documents open, there may be
several objects lying around, but only one will be in the re-
sponder c h a i n ~ t h e one associated with the active window.)
In this way, the command is sent appropriately. You need to
add actions to First Responder in the main nib for any menu
commands that act on objects in other nib files; you may need
to add other such actions as well.
In this chapter, all of the objects in the nib files have been
dragged from palettes. This is correct for most interface ele-
ments. However, if you have invisible objects (such as con-
trollers of views or data structures), you instantiate them by
selecting the appropriate class in the Classes pane and then
choosing Instantiate from the Classes menu. An instantiation
of the class appears in the Instances tab.
Project Builder supplies two Carbon templates: one for nib-
based applications and one for non-nib-based applications.
Using nib-based applications means that you can use Inter-
face Builder to design your interface.
The main difference you will see in using Interface Builder
with Carbon applications is that the outlets and actions are
gone. You design your menus and windows, but there are no
connections to set. You must programmatically handle the
events. But Interface Builder provides significant help in set-
ting all this up, as you can see in Figure 12-24.
Perhaps the most important factor is the c o m m a n d identifi-
e r i e as r in this case. That is the c o m m a n d ID that you will
be able to isolate in your event-handling routine. In a varia-
tion of the code presented in "Programming the Event Han-
dler" on page 165, you can write this section of code in your
event handler:
You simply place the appropriate case element into your han-
dler, and you carry out the actions for the button you created
in Interface Builder. (You can follow the Interface Builder and
Project Builder Carbon examples for step-by-step guidance
through this process if you want.)
If you create a nib-based Carbon application from the Project
Builder template, the basic code will be created for you. First,
the nib (called main, by default), is created:
Then, the main menu is extracted from that nib"
The window is also extracted"
The nib is disposed of (its contents having been extracted):
The window is shown, and the event loop is started"
Interface Builder lets you design interfaces for both Cocoa and
Carbon applications. With Cocoa, you can also use it to make
connections between interface elements and the outlets and
actions in your Cocoa code.
Interface Builder can be used not only to help implement your
application, but also to assist in prototyping, as the next chap-
ter shows.
This Page Intentionally Left Blank
With Project Builder and Interface Builder, you have incredibly
powerful tools that let you build an application in record time. The
temptation is to think that you can use them to build an application
quickly. You can do that, but you can also use them to build proto-
types of your application. It may sound boring or seem a waste of
time, but if you plan to build your application from scratch two or
even more times, it will be more robust and more successful.
Far too many projects are done simply by writing code, compiling it,
and then moving on. If you are a professional developer or if you are
a serious student or hobbyist, and if you value your efforts and want
to write good (or even excellent) code, you need to recognize that just
getting something to compile and run is not good enough.
This chapter examines the roles of prototypes, ways to shape the in-
terface, and ways to create the testing environments you need to
bring your project to fruition. You can use design tools such as Mac-
romedia Director for prototyping, but you can also use the quick de-
velopment tools in Project Builder and Interface Builder to do so.
Prototypes are mock-ups of your application (or parts of it)
that to a greater or lesser extent resemble what you think the
final product will look like. In the planning phase of your
project, proofs of concept are used to make sure that what you
want to do can be done. Once you have started to actually de-
velop your project, you use prototypes to explore alternative
design strategies~both internally and externally.
Many people do not understand how to use prototypes effec-
tively. They can be used as general practice for the main
project, but they also can be used very effectively to explore
specific areas. Focusing your prototypes (there can be many)
will mean that your final project can proceed more smoothly.
Sometimes a prototype is used to address a specific question
that arises in development. For example, if you are new to
Mac OS X programming but have a background in C++ pro-
gramming on another platform, you might want to try coding
part of your application in MacApp and Carbon using the
C++ language with which you are familiar. You might want
to also try coding that same part of your application in Cocoa,
using either Java or Objective-C.
If you keep an open mind, you will probably discover that
there are pros and cons to each option. What many people re-
alize is that the bulk of the work is involved in designing your
application and its objects, and that the high-level design is re-
markably transportable.
Because it is so easy to develop with modern tools such as
Project Builder/Interface Builder, and because object-orient-
ed frameworks like PowerPlant, MacApp, and Cocoa are so
efficient, it is often much faster to actually conduct such an ex-
periment rather than argue about which environment is best.
The biggest development cost is likely to be programmer re-
sources (whether you have a staff of 100 or are trying to fit
some extra hours into your weekend to get your pet project
done). Make the choice based on the people, not abstract ar-
guments about technology.
Fortunately, the developer tools included with Mac OS X al-
low you to perform such an experiment without purchasing
additional compilers or development environments.
A very common use of prototyping is to explore alternative
interfaces. Most of the time, computer programs involve visu-
alization of concepts~sometimes they are simple concepts,
such as words on a piece of paper, but at other times the con-
cepts are quite abstract, such as conformance to accounting
standards.
Part of the task of creating an application program is success-
fully identifying these concepts and providing visualizations
that make sense to the users. The first attempt is likely not to
be the best one, and the users need an opportunity to experi-
ment with interfaces. Prototyping lets them do so. (There is
more on this later in the chapter in "Shaping the Interface" on
page 287.)
In addition to providing a visualization of the concepts, you
may need to define the processing your program carries out.
Increasingly, corporate policies and procedures exist only in-
side their application programs: The days of separate policies
hammered out carefully in meetings are gone in many cases.
Part of the definition process is looking for loopholes and ex-
ceptions. The programmer needs to provide code that handles
all of the possible situations that may occur; corporate plan-
ners may not have done this.
You can describe these exceptional events all you want, but
when you put a prototype in front of a user and say, "What
should happen next?" it sometimes has a way of focusing at-
tention on the issue.
Sometimes you need an early version of the product to show
to people~documentation writers, investors, managers, mar-
keters, or even your friends. During the course of develop-
ment, the full application from time to time will not be usable.
You can keep a minimally featured prototype around to be
used for demonstrations. It is much better to have a robust
and reliable (but incomplete) prototype for these purposes
than to have a non-running (or crashing) real application.
The danger of these prototypes is that people can draw erro-
neous conclusions from them. You need to remind people that
they are not complete, and that the final product will look dif-
ferent.
If you are using new technologies, use a prototype to familiar-
ize yourself with the tools you will be using. The first Cocoa
application you write will probably not be terrific (and that
also applies to your first Java application, your first Pascal
program, and so forth).
Practicing with tutorials can be very useful, but taking the
time to write something that actually might be used in your
application is even more useful. Treating it as a throw-away
training experience is the most useful of all.
Finally, the skunkworks aspect of prototypes cannot be ig-
nored. More than one project has seen the light of day as a re-
sult of a prototyping experiment that took off and was carried
out without (or even despite) management's supervision.
All of these uses of prototyping rely on the ability to quickly
develop those pieces of an application that are the subject of
inquiry. Project Builder and Interface Builder are unmatched
as prototyping tools.
While you are prototyping and developing your design, the
interface gets the lion's share of attention. The world of appli-
cation interface design is still evolving, and although stan-
dards are taking shape, there is still not a consensus as to what
skills are required to design successful interfaces and to cri-
tique them. Everyone has an opinion (and not too many peo-
ple have logical arguments to back up their opinions). Unless
you are designing a work of art on the computer, your major
focus is usability and clarity: People should be able to use the
interface, and they should be able to understand the informa-
tion that it conveys.
Use Interface Builder for prototyping all phases of your appli-
cation. Not only can you easily create w i n d o w s (and alterna-
tive versions of windows), but you can also create output
displays through Interface Builder.
Whereas in the application itself users will click a button
named Compute or Go and cause the program to generate re-
sults, you can link the Compute or Go button to a new win-
dow that contains results you have typed in yourself. In this
case, you are not worrying about the calculation, you are con-
cerned about the best way of presenting the results to users.
Typically, time with users is scarce, so make the most of it. If
you have two or three output displays, present all of them to-
gether. Some users are so impressed with any display (and so
pleased to be asked their opinion) that they will agree to al-
most anything. Showing them several alternatives (not too
many) indicates that there is a real choice to be made and that
you do want them to pay attention.
In designing interfaces, try to observe real users working with
the interface. This can be done in a formal lab where you sit
behind a two-way mirror, but you can also do it informally at
a user's desk.
Your job at this point is to watch and listen. Do not show users
how to use the interface, and certainly keep your hands off the
mouse and the keyboard. Watch the mistakes they make (at
this stage of the game, those mistakes are likely to be your in-
terface design mistakes).
Because the design process is iterative, you need to preserve
innocent users~people who have not been part of the design
process. Remember that the users of your software may well
approach it without the background of your testers, so you
need to test the final interface on people who have not been
through the testing mill.
Once the prototypes have served their purposes and your full
project is under way, you need to be prepared to test the code
that is developed. Setting up test schedules and test environ-
ments has to be done very early in the project.
If the project is big enough, you may be able to have a separate
testing staff. It is very hard for the people who have actually
developed a project to successfully test it and find errors in it.
This applies to projects of all sorts. This book, for example, has
benefited from editing and comments from close to a dozen
people at the publisher (Morgan Kaufmann in San Francisco),
the production staff at Academic Press (in Boston), individu-
als at Apple, and a variety of other people. In reviewing early
drafts of this book, each of those people has found typograph-
ical and other errors that none of the others found.
Unit testing is also sometimes called programmer testing. It is
the testing that an individual developer does on a component
that is created. It should include all of the relevant aspects of
testing~functionality, failures, and interface.
System testing involves testing the product as a whole. When
a testing staff is involved, the staff usually picks up at this
stage after the individual (programmer or unit) testing is com-
pleted.
The first test of a product is that it does what it is supposed to
do. Unfortunately, for many products, the testing stops here.
You have to test that the program fails properly. Error mes-
sages should be provided, and they should be correctly
spelled and should not themselves cause further problems. It
is very common that error-handling routines themselves fail;
this is because the code is rarely executed and even less fre-
quently tested.
You also need to test interface errors~errors that come in
from the outside world. They can be user errors, but they also
can be errors involving other applications.
Too many occurrences of the same interface error may sug-
gest a problem with the interface design. In other cases, you
merely need to make certain that the error is caught and han-
dled properly.
You cannot just play around with a program to test it. You
need a test suite that provides a controlled way of exercising
as much of the product as possible.
Regression testing is a highly controlled form of testing
changes to applications. When a change is made, it is t e s t e d ~
and the entire test suite is rerun. In environments where soft-
ware reliability is critical (financial services, for example),
such testing is essential.
Changes during the testing process need to be controlled for-
mally. Normally, such changes are bundled together so that
test suites and regression testing can be done as few times as
possible.
Test suites can simulate functionality of a product, but they
cannot always duplicate real-life conditions. For example,
timing issues (and the problems that arise in multithreaded
applications) are very hard to duplicate in a testing lab. For
this reason, public or beta testing in real-life conditions is of-
ten added to the mix.
When you are satisfied that you have done as much as possi-
ble, you can let people actually use the product. This type of
testing is not done in a lab, but happens wherever people use
the product. It is relatively informal and uncontrolled, and as
a result, you normally need quite a few beta testers to get
good feedback. After all, not everyone will use the product ex-
tensively; those who do, may not encounter problems. Even
those who encounter problems may not report them.
Did you participate in the public beta testing of Mac OS X?
Did you find errors or have comments? Did you send them to
Apple? It is just like voting: If you do not make your voice
known, you have no legitimate right to beef.
Beta testing is sometimes used for other purposes, including
getting feedback on general product issues, marketablity, and
the like. It also is used for major software products to generate
publicity and to draw attention to the forthcoming product.
Users should test their software~particularly if they rely on
it for critical processing. During the period of concern over
Y2K problems, one startling discovery was that many indi-
viduals and corporations had no idea whether their software
worked properly.
In the case of shrink-wrapped, mass-market products, flaws
are often known. However, in the case of vertical market soft-
ware or custom-written software, bugs are not always discov-
ered.
It is common for users to install upgrades to their software
without understanding what those upgrades will do. You
should encourage users to create a test environment so that
they can find these things out before problems occur.
It is not always easy to go to users (who may in fact be your
employers) and tell them that you think there are flaws in
your code. But in the long run, including users in the test sce-
narios will make for better products and better relations.
Using the quick development features of Project Builder and
Interface Builder, you, your users, and your developers can
play with a remarkably lifelike version of your application.
The sooner this happens, the better, because changes made to
prototypes and pseudocode are always cheaper than changes
made during the actual implementation process.
This Page Intentionally Left Blank
Somehow or other people have gotten it into their heads that help~
at least in the world of technology~is bad. For developers, it seems
to be an admission that their elegant interfaces are not perfect (peo-
ple have trouble understanding them). For users, the mere existence
of help and assistance seems to threaten their independence and su-
periority over an inanimate chunk of silicon and plastic.
Maybe it is a sign of the times: Help (and helplessness) seem to con-
jure up a long-distant world of strapping damsels in distress and co-
quettish knights in shining armor. Today, everyone just knows how
to do everything~and if you don't, you wing it. Or so it seems.
Perhaps this strange antipathy to help and assistance can be over-
come by recognizing that help is not some weird afterthought in a
software project but instead is part of the entire suite of documenta-
tion and information that makes the product usable and makes peo-
ple understand what they can do with it.
This chapter helps you understand how to develop help and assis-
tance on Mac OS X. The technology (Apple Help and the Help
Viewer) goes back to Mac OS 8.6, so it is nothing new to old hands
at the Macintosh~both users and developers.
Your application is just a bunch of code that requires a user's
actions to place it in motion. How a user works with your
code and what is done with it depends on your code, on the
user, and what the user understands about the code.
This range of information about the code is provided by a host
of different mechanisms and media, one of which is help. Fol-
lowing is a s u m m a r y of the most common communication
tools for software.
Documentation is printed or PDF online documentation that
users can refer to. It may include step-by-step tutorials as well
as discursive examples, endorsements, questions-and-an-
swers, and so forth.
Increasingly, PDF versions of documentation are placed on
vendors' Web sites (and on internal sites for internal custom-
written software). This has two very important impacts on the
way in which people use documentation:
0 Because the documentation can be located, read, and
printed on demand, most people know where it is and
how to get it. Missing manuals are not a major prob-
lem.
0 Because documentation is available online, you can no
longer assume that readers of your documentation
have your product. Many people read or scan docu-
mentation before buying a product.
Advertising and promotional materials also provide general
information. Together with documentation, they help people
understand what they can do with a product. (In many cases,
the vast majority of users do not know most of the features of
the products that they use every day. This is particularly true
of office productivity tools.)
Onscreen information is the material that is presented at all
times to a user. It consists of the names of interface elements,
snippets of text ("include your area code with your phone
number"), and the like. It is chiefly characterized by being
there whether the users wants to see it or not.
Note that much information on screens~particularly crowd-
ed o n e s ~ i s ignored.
The user may seek out documentation (and even advertising);
more often those media require little, if any, action on a user's
part. Help, on the other hand, is provided only when the user
asks for it. It is a very different type of communication. You
should recognize several important principles of help.
Impasse and Frustration People ask for help when they can-
not do something. In very special cases (chiefly flirtation or
extreme cases of obnoxiousness), people do ask for assistance
in tasks that they can do, but these situations are rare in the
world of software.
Your user is frustrated. Everything that your assistance does
should be focused on getting the user back on track. This leads
to the second principle.
Help should always be task-oriented.
"This is the toolbar" is not help. It is part of a tour or travel-
ogue through the interface. It does not matter to the user what
you can do with the toolbar~the user wants to print or send
an email message. If the toolbar can do that, fine; if not, who
cares?
If the user is trying to do something that is illogical or impos-
sible, your help must point that out, but it should be pointed
out in the context of helping the user do what can be done.
Sometimes this is impossible: There is just no way that you
can create a movie using an email program, in most cases. In
addition, if the user is truly off base, your prepared help is
likely not to be of any help (you really were not expecting peo-
ple to search for the Create Movie menu item in your email
program). Leave some opening for u s e r s ~ a technical support
number or email address, a Web site, or the like.
elements when you refer to them in documentation and
advertising. This is because you cannot insert an image of the
object in question whenever you refer to it.
In your documentation and advertising, it is critical to name
interface elements consistently so that people can understand
the imaginary interface world you are creating. In online help,
however, you can refer to objects on the screen much more
simply. Tool tips, for example, appear next to objects. You do
not have to say "Drag and drop images to the Image Well" or
even "Drag and drop images here"; instead, you can say
"Drag and drop images" because the location is identified by
the mouse position and the tool tip that appears.
If you name objects in your online help, people will go look-
ing for them. Users are remarkably resourceful, and will pro-
vide rather lovely explanations for w h y they assume that the
Image Well is not the object to which the mouse is pointing
and to which the tool tip is attached.
gram, you must assume a knowledge of menus, windows,
buttons, and other basic controls. True, some users are
amazed to learn after years of using a Macintosh computer
that they can resize a window, but such users are the excep-
tion rather than the rule.
In the particular domain that your application focuses on, rec-
ognize experience as well. If you are providing a program to
help keep track of sheep- and goat-breeding, the phrase
"small ruminant" requires no explanation.
In general, users like a software application to match their lev-
el of expertise closely. They will endow it with all sorts of
imaginary attributes in order to do so. Do not spoil the illu-
sion by breaking this bond either with over simplification or
with sudden confusing jargon.
Don't Be Cute Finally, remember the first principle" Your
help-needing user is frustrated and at an impasse. This is the
wrong time for cuteness.
Help buttons (usually indicated with a question mark) launch
application help. Since such buttons are usually located on
specific windows, the program can launch fairly appropriate
help information for each one.
Help Viewer is the foundation of Apple Help; it is used to dis-
play information for the user. Some applications use other
help delivery mechanisms (this is particularly true of cross-
platform applications that need to provide consistency within
their applications).
Tool tips and help tags are brief messages that appear if a user
holds the mouse over an interface element for a few seconds.
The easiest way to create a tool tip is in Interface Builder: Se-
lect the interface element, choose Help from the pop-up at the
top of the Info window, and type in your tool tip as shown in
Figure 14-1.
(The two terms~tool tips and help tags~are similar in mean-
ing, but tool tip is used in Cocoa and help tag is used in Car-
bon.)
The field in which you enter the tool tip in the Info window is
not large; in fact, it is probably a bit larger than the best tool
tips are. In writing tool tips, you should consider these issues:
Add information; if you have nothing to add, omit the
tool tip. Not every interface element needs a tool tip.
Make the tip active, not descriptive. In the example
shown here, the user finds out what to do ("drag and
drop") as well as additional information not obvious
from the interface ("TIFF and JPEG images").
Limit the tip to one item. Do not write a tip that refers
to multiple interface elements. The one exception to
this is in the case of closely spaced objects such as ra-
dio buttons. You can attach a tool tip to the view that
groups those button so that i t ~ t h e combination of
b u t t o n s ~ r e c e i v e s the tip.
As you can see from Figure 14-1, you cannot provide
alternative tips for alternative states of the object.
W h a t you write m u s t apply to selected/unselected
items, active/inactive controls, and so forth.
Contextual m e n u s appear w h e n the user holds d o w n the CON-
TROL key while holding the mouse button over an interface el-
ement to which a contextual m e n u is attached. You create
contextual m e n u s in Interface Builder: Simply drag a m e n u
from the palette into your nib file and add the c o m m a n d s that
are relevant. Attach those c o m m a n d s as you normally w o u l d
attach any m e n u c o m m a n d s to interface elements and actions.
Next, attach the contextual m e n u to the interface element.
H o l d i n g d o w n the CONTROL key, drag from the element to the
N S M e n u as s h o w n in Figure 14-2.
In the Connections pane of the Info w i n d o w , select the m e n u
outlet. All views have a m e n u outlet, so you can attach a con-
textual m e n u to any type of view in Interface Builder.
You can create a single contextual m e n u and attach it to a va-
riety of interface elements if they all have the same contextual
m e n u s and actions. If some of the m e n u c o m m a n d s have dif-
ferent meanings (such as Clear, which might clear a particular
field), you cannot do so.
Remember that m a n y standard interface elements (such as
text fields and text views) come with their o w n contextual
menus. If your w i n d o w has a b a c k g r o u n d view, you can con-
nect it to a contextual m e n u (you cannot connect a w i n d o w to
a contextual menu).
Contextual m e n u s can address the task-oriented aspects of
help that have been described earlier. They also can serve the
p u r p o s e of answering, "What can I do now?" in addition to or
instead of " H o w do I...?"
Contextual m e n u s also can be used to extend the interface.
This is sometimes a risky avenue to take, b u t it works in some
circumstances. One example is the case in which you m a y
w a n t to open an application package in the Finder to see its
constituent files. Using the Info w i n d o w , you can open its re-
sources, but the various files are normally not s h o w n in the
Finder. The contextual m e n u that appears w h e n you CON-
TROL-click on a Finder icon includes a Show Package Contents
c o m m a n d that you can use to open it up in its o w n Finder
window. This is a typical p o w e r user feature; however, be-
cause it is included with a c o m m o n feature (contextual
menus), there is no guarantee that only expert users will use
it.
Even so, this approach can be a useful way of providing two
sets of commands to users of your application. Just realize
that there may be unforeseen side effects from people explor-
ing commands that you thought were hidden.
Finally, the Help menu at the right of the menu bar provides
users' entrance to Apple Help and the Help Viewer. Help
menus have undergone changes over the years as interface
designers have come to understand the most productive way
of organizing assistance.
At one point, all help was collected in the Help menu, result-
ing in a plethora of help commands. What this meant was that
the frustrated user not only had to confront the inability to
complete a task but also had to deal with the mystery of where
the key to the problem might be located.
With Apple Help, a single entry (YourApp Help) is provided
for entrance to Help Viewer. From there, the user can navigate
to other help resources. This seems to work most effectively.
Help Viewer displays help in windows like that shown in Fig-
ure 14-3. The window layout is standard across all applica-
tions. The body of the help material is written by you using
HTML 3.2. This means that plug-ins, forms, and Java are out.
Basic formatting, headers, images, and anchors are in.
Full documentation for Apple Help is available at h t t p : / / d e -
veloper.apple.com/ue/resources.html. Apple Help is avail-
able on Mac OS 8.6, OS 9, and OS X; on OS X you can access it
from Classic, Carbon, or Cocoa. The links on the user experi-
ence page cited here will help you find the documentation;
much of it is located under Carbon, but you can use it from
Cocoa, too.
In the Help Viewer w i n d o w shown in Figure 14-3, you can see
an image tag, a header (H1) t a g ~ T a k i n g pictures of the
s c r e e n ~ a n d several paragraphs of text.
At the bottom left, an anchor lets users open the Grab applica-
tion (for which this help is provided).
At the top of the window, users can search your help; they can
also use the button at the lower left to go to the main help win-
dow.
If a user decides to search, the current set of h e l p ~ k n o w n as
a help book~is searched as you can see in Figure 14-4. Search-
ing is based on text as well as on keywords that you specify in
a special tag at the top of a help page. It is an HTML meta tag,
and it looks like this:
You do not need to repeat keywords that are in the body of the
page; however, concepts that are not referenced by name are
useful to add to keywords. In addition, misspelling or alterna-
tive spellings that users may indulge in should be provided as
shown in the previous example ("QuikTime').
You can split a single page up into segments; each one can
then appear separately in the search results.
The results of the search are summarized based on yet another
meta tag. In the first result shown here, the following tag
would appear at the top of the HTML file:
The user can select any of the results to view. If they are not
satisfactory, the Help Viewer instructions invite users to
search all of h e l p ~ t h a t is, all installed help books. The results,
as you can see in Figure 14-5, come from a variety of applica-
tions.
A meta tag that is used frequently on Web pages lets you con-
trol indexing with more detail:
follows:
9 INDEX (the default)
9 NOINDEX (skip the entire p a g e - - u s e for tables of
contents)
9 KEYWORDS (use only keywords, not the text)
9 SEGMENTS (indexes only the segments on a page)
9 ANCHORS (indexes only the anchors on a page)
If a user chooses the button at the lower left, the systemwide
Help Center containing all currently installed help books is
shown as in Figure 14-6.
To prepare an index, you drag the folder containing all of
your help files onto the Apple Help Indexing Tool; all relevant
indexes will be created. This tool is available as part of the
Carbon SDK; further information on using it and on prepar-
ing help is in that SDK as well as on Apple's Web site. You
also will find documentation there on more advanced topics
such as integrated Web-based HTML pages with your help
files.
You can place anchor tags in your help files; from the HREF
attribute you can reference several Help Viewer-specific sche-
mas.
Help Center To load the Help Center page (shown in Figure
14-6), use the following syntax:
The Developer Help Center is loaded with
This example also demonstrates that you must use HTML-
compliant names. That is, special characters~such as a
space--must be encoded; %20 is the code for a space.
A canned search in all system help books looks like this"
The first example produces a result such as that shown previ-
ous in Figure 14-4; the second produces the results in Figure
14-5.
Apple$cript To start an AppleScript, use this syntax:
A single string is passed to the AppleScript. You specify it as
follows:
It is your responsibility to make certain that the AppleScript
can accept and properly process such a string.
know its location by using the following syntax:
Additional commands are described in Apple's documenta-
tion. Note that most of Apple Help is also available through a
public API; you can carry out these commands and open the
Help Viewer programmatically.
All of the general comments about help that were provided at
the beginning of this chapter apply to Help Viewer content. In
addition, two important points should be kept in mind.
Users appreciate the "do it for me" feature
of AppleScript. There has been some concern that providing
too many AppleScript choices would create a group of users
with no understanding of what they are doing, but research
by Apple has shown nothing but contented users. Remember,
it may take you a day or two to develop an AppleScript, but
you will be saving many users many hours and days of
work~each.
Users click on buttons; they move
scroll bars; they have been trained to interact with the inter-
face. You can add images to your help content, but avoid di-
rectly placing interface elements (screen shots or parts of
screen shots) into the help content. Users will click the image.
If you feel that you must put an image of all or part of the in-
terface into your help content, make it clear that it is an image.
You can provide it with a jagged border that looks as if it is a
scrap of paper; you can also "break the frame" of the i m a g e ~
provide an arrow pointing into the middle of the i m a g e ~ s o
that it is clear that it is not a set of live controls.
The best choice is to keep the interface where it i s ~ o n the
desktop and in application w i n d o w s ~ a n d to keep the very
special Help Viewer and its functionality separate.
One thing does not work: Do not place text in the help win-
dow saying "This is only an image, do not try to click the but-
ton." It is like waving a red flag at a bull.
From Cocoa or Carbon, it is very easy to install Help Viewer
content through Project Builder. Here is the recipe.
Prepare your help files using the meta tags
described here and in the Apple documentation. Place them
all in one folder.
Make certain that all help files have a suffix of
Drag the folder to the Apple Help Indexing
Tool (in the Carbon SDK) to index all of the files.
Click the Target tab on the project
structure pane. Inside the Application Settings tab, set the fol-
lowing:
0 Set I d e n t i f i e r (under Basic Information). This
must be a unique name for your application. The Ap-
ple examples use the Java naming convention to pro-
vide unique names; you can follow that. It is the
reverse of your domain name followed by a name that
is unique within it. Thus, the identifier for sketch is
com.apple.CocoaExamples.Sketch. The item in the
property list that this sets is C F B u n d l e I d e n t i f i e r ;
it must be set and must be unique for help to work.
@ Use the Expert button to set C F B u n d l e H e l p B o o k -
F o 1 d e r to the name of the folder within your project
that contains the help files (this is the folder that you
indexed). Normally, this folder is inside the En-
glish.lprog (or French.lprog) folder on disk. The name
is the name of the folder within your project; it is not a
fully qualified path name.
@ Also with the Expert button, set CFBundleHelp-
B o o k N a m e to the title of your help book as defined in
your title page using a meta tag like the following. Re-
place "Diary Help" with your own help title; the name
AppleTitle is used for all help files.
Whether your application is a shrink-wrapped consumer
product or an in-house application for a single department (or
single user---even yourself), it is not complete without an ap-
propriate level of assistance and help.
Apple Help is available in both the Cocoa and Carbon frame-
works, and it provides an HTML-based help system that can
integrate Web updates dynamically.
When you have finished with your help system, you are ready
to package your product for distribution. The next chapter
shows you how to do that.
This Page Intentionally Left Blank
On the original Macintosh, applications were more or less based on
a single file. Over time, that single file, with its data and resource
forks, was joined by various support files. In addition, user prefer-
ences (not to mention user data) cluttered the application; these files
showed up in a variety of folders (Preferences inside the System
Folder, for example). As a result, installation became tricky. Fur-
thermore, moving an application from one computer to another was
not always easy~there were many pieces to remember.
On Mac OS X, applications come in self-contained packages that
group their various files together. User preferences show up in each
user's Library folder, and documents are normally placed in the
Documents, Pictures, and Movies folders for each user.
To provide easy-to-install (and easy-to-move) applications to users,
it is best to provide them with a single thing that they can work with
for installation and reinstallation. Three basic mechanisms are
available on Mac OS X:
You can use the output of Project Builder to create an in-
stallable application.
You can prepare a disk image that, as a single file, can be
sent over the Internet and then opened as a disk image on the
receiving computer.
You can use Package Maker to create a package that will be
installed by the installer.
This chapter shows you how to do all three. It ends with some tips
on testing and troubleshooting installation problems.
A bundle contains all of an application's resources, including
its code. The entire bundle appears as one file to users; they
can move it around as they see fit. If they use the Info w i n d o w
to look at an application, they can see its localized resources
from the Application Files pane. To open an application's
bundle to see its contents, users need to use a contextual
menu.
CONTROL-click on an application to bring up the contextual
menu, and then choose Show Package Contents to open a
Finder w i n d o w that shows the application's contents. Note
that this is a special Finder window; you can navigate d o w n
into the folders of the application, but you cannot navigate up
and out of i t ~ t h a t is, you cannot move into the application's
containing folder from such a window. (This process is s h o w n
later in this chapter in "Creating a Disk Image" on page 317.)
Application bundles are folders whose names end with the
.app extension. The Finder hides the extension and presents
the folder as an application icon so that to the user it appears
to be a single file.
In addition to applications, other types of bundles are frame-
works, debug or profile versions of applications, and plug-ins
that are loaded on demand by applications (including Inter-
face Builder, which relies heavily on palettes).
Normally, applications are installed either in the systemwide
Applications folder (/Applications) or in an individual user's
Applications folder (~/Applications). They also may be locat-
ed on the local area network.
The Finder looks in these locations for applications; Cocoa
looks there for services. Applications located in other places
will probably function properly, but they may not appear
properly in the Finder and their services may not be exposed.
Because an application bundle appears as one file, dragging
and dropping it is the easiest way to install and remove it. An
installation program (such as Installer) can be used to handle
more complex installations.
When you use the Apple Installer, you combine the applica-
tion bundle and a variety of other files into an installation
package(a file with a .pkg suffix). The Installer reads the pack-
age file, manipulates it (decompressing its contents, perhaps),
and then installs its package in the appropriate locations.
The simplest way to create an application bundle is to use the
Project Builder Deployment build phase as shown in Figure
15-1.
You normally do not need to do anything here" The figure is
presented to show what Project Builder does for you. Note
that in the Groups & Files view of the project structure pane
at the left, all of the project files have been organized~as you
normally do. In particular, note the Diary Help folder that is
located within the Resources folder.
At the right, the highlighted line shows that Project Builder
has automatically included the Diary Help folder in the bun-
dle resources. It has noted that one variant (English) exists.
The rearranging of file names (involving lprog.English) is au-
tomatic.
When you build a deployment version in Project Builder, you
do have to make a few adjustments in the Build Settings pane.
In particular, you need to set a location for the compiled ap-
plication to be placed in. This is shown in Figure 15-2.
The variable $HOME specifies the user's home directory.
Thus, this application will be installed in a user's Applications
folder, not in the systemwide Applications folder.
On successful completion of the build, the application~
viewed as a single icon in the Finder~is placed on disk. You
can open it using a contextual menu as shown in Figure 15-3.
Choose Show Package Contents to see the contents of the
wrapper folder that is the application bundle.
The contents of the application bundle are shown in Figure
15-4. Note in particular the Diary Help folder; it is located in-
side English.lprog.
Next to the Diary Help folder are the two nibs that the appli-
cation uses. The application executable code is located in the
MacOS folder (along with any Classic executable code that
may be present). This collection of files and folders is similar
to the contents of the project folder, but there is no source code
here.
Note, too, that you cannot scroll the browser in Figure 15-4 to
the left: The Contents folder inside an application folder is not
part of the Finder's file hierarchy, and you cannot look at the
folder in which it is located. You can access all files and direc-
tories within the application bundle from the command line
(but the Finder access described here is usually sufficient).
A somewhat more complex method of creating a single file for
users to install your application is to create a disk image. This
is suitable for sending via email or transferring using FTP.
Transferring an application bundle over a network may cause
problems because it will appear as a folder or directory; its
special application qualities appear only on Mac OS X, and
mostly only when the Finder is involved.
Project Builder's multiple target structure allows one target to
depend on another. When you combine the dependencies
with the ability to have a target that consists only of a shell
script, you can create the following elegant process. Simply
put, it makes your project's compile-and-build target a depen-
dent target of a legacy target that runs a shell script, which it-
self packages the newly built application in a disk image.
Figure 15-5 shows how you set up such a process. Create a
legacy target (such as Disk Image Creator). In the Custom
Build Command pane of the selected target, make three en-
tries"
1. Set the tool to / b i n / s h.
0 Set the arguments as shown. Specify the size of the
disk image (8000 is used in this example), and set the
name of the image to be created (replace outimg with
your own image file name).
Q Locate the directory in which the files exist (your
project directory).
9
When you build a deployment version of this target (set the
deployment build phase in the lower left, as shown), the script
will be run to create the disk image. If your build is lengthy,
you can launch the whole process from the command line.
Use c d to change the directory to your project's directory, and
then type
(You can also drag and drop your project's directory into Ter-
minal: type c d and a space, then drag the folder onto the com-
mand line.)
Here is the script you need to use. It should be added to your
project but not attached to a target.
The Apple Installer is used to install Mac OS X itself and many
other software products on your computer. Its initial screen is
shown in Figure 15-6.
Using the installer rather than drag-and-drop is a good idea
when the installation is complex and when subsidiary files (li-
censes, Read Mes, and the like) need to be managed.
An installation package contains one or more application
bundles; these may be archived automatically and dearchived
during the installation process. In addition, other files and
scripts can be included in the package.
Package Maker is included with the developer tools, and it al-
lows you to easily create installer packages. To begin with,
create a distribution root folder (DSTROOT) and assemble the
files that you need to include in the package. Normally, this
will be the Project Builder output from a deployment build,
but you may include other files.
When you first launch it, the control w i n d o w shown in Figure
15-7 appears. The first two entries are for the DSTROOT direc-
tory in which you placed the Project Builder output; the re-
sources directory is where you should place the additional
files that are needed during the installation.
If you include a ReadMe file with a suffix of .txt, .rtf. or .html
in the resources folder, it will be displayed in the Important
Information pane of the installer.
If there is a file named License.txt, License.html, or License.rtf
in the resources folder, it is displayed in a sheet at the appro-
priate point in the installation process.
The other fields and options on the Package Maker form are
self-explanatory. Additional information is available from the
online help included with Package Maker.
Be sure to test installations of your software. Users typically
do not do many installations, and they m a y install your soft-
ware only once. Your installation should work the first time.
If it does not, you may have lost your chance to have people
use your software ever again.
The basic test of an installation should be done on a computer
that has never had your software installed on it. This is be-
cause if your installation accidentally does not include some-
thing that happens to be on your test computer, you will not
find the mistake.
One common w a y of handling this testing situation is to keep
your hard disk partitioned into two sections. Keep one or two
gigabytes for a cleanly installed operating system; use the rest
for your work. When you need to test an installation, reformat
the small partition, install a fresh copy of Mac OS X, restart
with that partition as the startup disk, and see if the installa-
tion works. If it does not, the most basic user installations will
fail.
You should do additional testing in other environments (par-
ticularly if there are certain configurations that you know will
be used). In addition to the installation, test that everything
works properly. Pay particular attention to first-time bugs
that cannot be easily reproduced. At one time, for example,
MacApp applications crashed if you attempted to print a doc-
ument on a computer on which no document had ever been
printed since the operating system was installed (in other
words, on Mac OS 7 ~ w h e r e this o c c u r r e d ~ t h e Chooser had
never been used to select a printer). The typical response of
users (and testers) was to test if there was a problem with
printing. They printed s o m e t h i n g ~ a n d selected a printer in
the Chooser to do so. They then ran the MacApp application
again, and all was well. Their troubleshooting actually solved
the problem, and it was some time before the true bug was
discovered.
Wherever possible, use a simple drag-and-drop installation
for your applications. On a single computer or on a local area
network, you can use the application bundle created by
Project Builder to do this.
If you need to send the application bundle across the Internet,
consider packaging it in a single file such as a disk image. That
single file will be handled properly by other operating sys-
tems it may encounter on its travels.
Finally, consider using Package Maker and the Apple Install-
er for more complex installations.
In part because all of your source code is stored electronically, it is
important to keep track of it and the various versions of it. Whereas
early programmers could always go back to their punched cards,
programmers now cannot go back to yesterday's version (or the ver-
sion from 10 minutes ago) unless some kind of management struc-
ture is in place.
Project Builder incorporates the Concurrent Versions System
(CVS) that is widely used for open-source projects. You can access
most of the commands that you need through its SCM (source code
management) menu.
The basic idea behind source code management is that a cen-
tral location~called a repository in CVS-~contains all versions
of all files associated with a project. Each version of each file
is identified by date and with an informational note that is
placed there by a programmer.
You check out files to work on them; you check them in (with
notes) when you are done with them. This means that you do
not have to save entire copies of a project folder as you exper-
iment.
Source code management tools function in one of two ways:
0 When a programmer starts to work on a file, it is
checked out. No other programmer can check out a
modifiable version of the file. (Programmers can also
check out read-only versions of files without affecting
other people, but they cannot modify them.)
Q Anyone can check out a file at any time. When it comes
time to check it in, the programmer must merge it with
the then-current version of the file (which may have
been modified in the meantime).
CVS uses the second mechanism. It is particularly well suited
to large projects on which many people may have checked out
many files but which may never be checked back in (the
checkouts are used for experimentation, for example). This
describes many open-source projects.
Because the check-in process requires the person checking in
the code to compare it to the current version, a source code
management system normally includes file merge and com-
pare software (as does CVS).
Source code management is essential on large projects; it is at
least as critical on small, one-person projects. It is used so that
versions of code can be i d e n t i f i e d ~ w h e n e v e r you reach a
stopping point, you can set a version to which you can return.
That m a y be automatically at the end of a day, but it m a y be
at the end of fixing a particular bug or solving a particular
problem. Programmers expect to be able to quickly revert to
any previous version of their software. This avoids the prac-
tice of storing copies of your code in folders with names like
"Friday Good" or "Tuesday Before Restructuring."
If you are used to working on your own, SCM may be a
change. Actually, it turns out to be very simple and conve-
nient. You set up your repository and put all your code in it,
and then you check it out as you need it. This means that if
you want to take your code with you on an iBook or Power-
Book, you just connect to your repository and check every-
thing out; you do not have to w o r r y about copying files. When
you need to synchronize files, you can easily do it through
Project Builder.
Project Builder provides access to the check-in and check-out
features of CVS. However, you need to set it up first. If you al-
ready have a CVS code repository on a network, you can skip
this step. Your network or project coordinator will provide
the information that you need.
Create the project as you normally would in Project Builder; if
you already have a project, you can start with it. Although the
whole point of using CVS is to keep a safe copy of your
project, start by copying the entire project folder just in case
something goes wrong.
Start by creating the repository for all of your CVS files. This
directory can be anywhere on your computer or local area net-
work, but it must be accessible to everyone who will need to
check files in and out. In many places, this directory lives on
a file server that is protected with an uninterruptible power
supply (UPS) and that is automatically backed up to tape or
some other medium on a regular (at least daily) basis. Note,
too, that this central repository can be of tremendous value to
outsiders. It should not be located on a public Web server un-
less you intend to make your code open source.
Once you have created the directory for your CVS files, use
Terminal to let CVS know where it is. You can set the environ-
mental variable CVSROOT for this purpose:
Use Terminal's drag-and-drop to drag the directory (folder)
from the Finder into this command line following CVSROOT.
code with your actual repository directory name.
All of your CVS projects will be placed in this directory. You
can change this directory from time to time by using the -d
option with CVS commands on the command line. That spec-
ifies a specific directory for one CVS command. You need to
do this if you are switching between a local code repository
and a networked one (such as Apple's Darwin repository).
Next, import your project into the repository directory you
have just created.
Go to the directory in which your project is located. Use the
c d c o m m a n d to change the Terminal directory to that directo-
ry (type c d, then drag and drop the folder onto the command
line--remember to leave a space after c d and before you drag
and drop the folder).
Next, use the c v s i m p o r t c o m m a n d to import the contents
of your default directory. The -m (message) option lets you
specify the check-in message; if you do not enter it, you will
be p r o m p t e d for it. After that, you specify three required vari-
ables:
The name of the project repository directory to be cre-
ated within the main repository directory. In the ex-
ample
11, A vendor name. For most purposes, you can simply
name the project. Di a r y is used for the vendor name
here. (This matters w h e n you are working with third-
party code that will need to be merged later on into
other CVS systems. For merging within your o w n re-
pository, you can set this to any value you want in
most cases.)
0 A release name. This, too, matters w h e n you are work-
ing with other parties. Here, S t a r t is used.
CVS will report if there are any conflicts: When you are set-
ting up a project, there should be none. You are using a new
directory for a new project.
You have moved all of your files into the CVS repository; n o w
you need to get them back again. The round trip will have
equipped them with the CVS information that lets you check
them in and out.
Go to a directory in which you want to work. To prevent any
possible confusion at this point, you might consider creating
a new directory in your Documents folder--calling it work
may keep it separate from other folders you already have.
Back in Terminal, change your directory to this new one: use
the c d c o m m a n d (type a space after it), and then drag and
drop the folder you want to use.
Check out the entire directory of files using this command:
where Di a r y is whatever vendor name you used in the im-
po r t command described previously.
The entire directory of files that you checked in should be
placed in your new directory. You can now quit Terminal and
move into Project Builder.
Open your project file in this new directory from Project
Builder.
After this, w h e n you open your project, Project Builder will
automatically add a column to the left of Groups & Files view
in the project structure pane as shown in Figure 16-1. If it does
not do so, see "CVS Preferences" on page 338.
Note that source code management in Project Builder is im-
plemented using CVS. In the future, alternative source code
mechanisms could be used. As a result, the more general
t e r m ~ S C M ~ i s used from here on.
Each file in the SCM repository will be identified with a sym-
bol letting you know its status:
Blank (space). Repository and local versions of the file
are the same. (Note this is based on the check-in infor-
mation; SCM does not scan the files to confirm that
they are the same. It is possible to fool CVS---but it is
not easy, and it is not a good idea.)
9 ? The file is not a SCM file.
9 U. The file on your disk needs to be u p d a t e d with a
more recent version from SCM.
9 A. You have a d d e d a file locally but not to the reposi-
tory.
9 R. You have r e m o v e d a file locally but not from the re-
pository.
9 M. You have modified a file locally, but not m o v e d it
to the repository.
9 C. A conflict occurred during a merge or update.
9 -. The folder is not k n o w n to SCM.
If you are w o r k i n g alone on a project and using SCM to keep
track of your work, the only symbols you will care about are
blank (no problem), M (modified), A (added), and R (re-
moved).
If you are w o r k i n g on a multiperson project, you also m a y see
UorC.
You can add, remove, or check in files to the repository
t h r o u g h Project Builder. Creating new projects or a d d i n g
folders (not files) to a project needs to be done t h r o u g h Termi-
nal.
You can select any file in the Groups & Files list and see its
SCM status by using the Show Info c o m m a n d from the Project
m e n u as shown in Figure 16-2.
This pane is available for files that are not under source code
management, but the version information is available only for
SCM files. Note the message column: When you have ver-
sions that go back several months (or years!), those messages
become increasingly important.
You can select any two versions of a file (COMMAND-click) in
this w i n d o w and compare them by using the button at the
lower right. Comparing files is one of the most important
tools in source code management. As Figure 16-2 indicates,
you can compare versions that are not consecutive. This is
particularly useful when a fix to one problem has introduced
another error and you need to go back to the last clean ver-
sion.
The FileMerge window is shown in Figure 16-3. Each file is
shown in is own pane, and you can clearly see additions, de-
letions, and changes.
FileMerge is a separate application with its own preferences,
as shown in Figure 16-4.
On multiuser projects, each user can have separate preferences.
This helps in navigating through files that others have modi-
fied. Additional preferences are shown in Figure 16-5.
When you have modified a file locally, it is marked with an M
as shown in Figure 16-6. When you are satisfied that you are
at a point where the code should be checked in, select the file
and choose Commit Changes from the SCM menu.
Remember that checking a file in is a w a y of protecting it from
accidental deletion or modification (unless the entire reposito-
ry is destroyed). On a multiuser project, you should not check
in code that does not work unless there are extenuating cir-
cumstances. (For example, multiple changes from a variety of
programmers m a y be required to implement a single feature;
until all are checked in, none m a y work properly.) On a sin-
gle-person project, you can use the repository for daily back-
ups, and there is no reason to worry about checking in b u g g y
code.
You will be prompted to enter a message as shown in Figure
16-7. This message will appear in the Info w i n d o w (see "Ver-
sion Info" on page 333).
Once the file has been checked in, it is no longer marked with
an M. Note that you must check in each file individually; in
Figure 16-8, you can see that one modified file is no longer
m a r k e d with M (it has been checked in), but the other one still
needs to be checked in.
One particularly helpful tool of code m a n a g e m e n t is the abil-
ity to quickly revert to a previous version of a file as s h o w n in
Figure 16-9.
To do this, you select a file in the Groups & Files view and
then choose Revert to Latest Revision from the SCM menu.
This lets you throw out your changes if you have been wan-
dering off on an unproductive track.
The Project Builder preferences include a CVS Access pane as
shown in Figure 16-10.
If you are having problems, make certain that CVS is enabled
here. Also, it is a good idea to save files before SCM opera-
tions. The radio buttons controlling w h e n SCM status is ob-
tained are most important in multiuser projects where file
status may change while you are working on files.
CVS servers manage many large projects (Mac OS X, for ex-
ample). They also manage open-source projects. If you want
to access Apple's open-source code for Darwin, for example,
you use CVS.
First, go to the Apple public source page (http://public-
source.apple.corn/) and register. You will need to select a
user name and password.
Then, you need to set your CVSROOT to the remote directory.
You can modify the CVSROOT environmental variable or use
the -d option in cvs commands. Here is the Terminal code to
modify the environmental variable for Darwin open source:
Then log in with
You should receive the following response:
Type your password, and you should be connected to the
code repository. You can then proceed to check out the source
code using the same check-out procedures outlined previous-
ly in this chapter.
The likelihood of any software development project moving
from start to finish without any interruptions, backtracking,
or revisions is minimal. When more than one person is in-
volved, the challenges of coordination are magnified.
Managing source code is a normal part of everyday, profes-
sional software development~even for students and hobby-
ists. Because Project Builder provides you with integrated
source code management, there is no reason not to use i t ~
and many reasons to do so.
This part of the book has led you from the initial planning of
a software development project through its prototyping, im-
plementation, and packaging. The next part of the book looks
at the details of writing for Mac OS X.
This part of the book shows you how to create Mac OS X applica-
tions. Each chapter focuses on a different aspect of functionality~
documents, windows, and the like. Many of these chapters refer to a
simple Diary application that is described in the first chapter of this
part. Sections of its source code appear with annotations in the ap-
propriate chapters. You can download the application (and the
source code)from the author's Web site~http://www.philmont-
mill.com. Select the Mac OS X area and then follow the link to Mac
OS X Developer's Guide.
For a complete reference to all of the classes in the Mac OS X frame-
works, refer to the documentation on the developer CD-ROM and
on Apple's Web site. The focus of this part of the book is on showing
you the sorts of things you can do and then pointing you in the di-
rection of additional information. You should have read Part L and
you should be familiar with the programming concepts described
there. If you need additional assistance, consult the Apple documen-
tation.
This Page Intentionally Left Blank
This chapter begins with a walk-through of the Diary application. It
continues with the code that you need to use to create that applica-
tion. As you will see, the application object in the Cocoaframework
is critical~but its default behavior is almost always satisfactory.
The boilerplate code that Project Builder creates for you is generally
usable without modification.
In the final part of this chapter, a brief summary of the Carbon ap-
plication object in MacApp is provided. You will alsofind a guide to
deciphering Classic and Carbon applications that have been written
without the benefit offrameworks (in case you need to modify or con-
vert such applications to Cocoa).
It is easier to understand programming concepts when por-
tions of code are at hand. The problem is always to have ex-
amples that are complex enough to shed light on real-world
problems but not so complicated as to require more explana-
tion of the example than of the concept.
One application program is used for many of the examples in
this part of the book. It is of moderate complexity, and it
touches on many of the issues that most Mac OS X developers
need to know about. Inside Diary, you will find the following
functionality:
Windows and views, including text fields and text
views, buttons, scrollers, and images
9 A drawer
9 A customizable toolbar
9 Documents that can be saved and reopened
9 Automatic dirtying of documents after changes
9 An undo feature
You will find wonderful examples from Apple on the devel-
oper CD-ROM. Among them, you will find TextEdit and
Sketch~very sophisticated authoring tools for text and
graphics. However, as many developers have found, the op-
portunities to write from-scratch editing applications are few
and far between. More often, the need to read and write struc-
tured data and to perform calculations on it is what needs to
be done. That is what Diary does.
Diary is a program that is designed to help people keep dia-
ries. People who keep diaries on paper often start either with
blank notebooks or with preprinted books that have space on
each page for a date or other identifying information.
Diary presents a more structured but still flexible approach to
the wide variety of diary-keeping. As is always the case when
you start to work on an application program, it is important
to define its scope and to know exactly how you and the user
expect it to work. (Even if you are both developer and user,
you need to come to this mutual agreement.) You have to un-
derstand the data you are working with before you can ade-
quately represent it in windows and views or store it on disk.
Here is the scope and purpose of Diary. It starts from the sev-
en types of diaries that Thomas Mallon describes in his excel-
lent book, A Book of One's Own 1"
0 Chroniclers: These people keep a day-by-day (or irreg-
ular) record of goings-on.
0 Travelers: Many people who do not otherwise keep
diaries or journals do so when they travel. Sometimes
these diaries are kept for their own sake; other times
they are kept to help identify photographs or video
clips as well as to keep track of purchases for customs.
0 Pilgrims" After embarking on a personal or spiritual
search, many people keep track of their progress (or
lack of it) in attaining inner goals.
0 Creators: Artists, writers, scientists~and even com-
puter developers~keep track of their experiments
and the development of their ideas and projects.
5. Apologists: These people need to explain or promote
themselves or their causes. As Mallon writes, they in-
clude not only politicians such as Nigel Nicholson and
Richard Nixon, but also "unappreciated artists; neb-
bishes turned killers; those denied their dreams be-
cause they were the wrong age, or the wrong sex, or
1. A Book of One's Own: People and Their Diaries, Thomas Mallon.
Ticknor & Fields, 1984.
just in the wrong place"; and "lovers, spurned and
scornful, hurt and bewildered, proud and defiant."
Q Confessors: Sometimes only a diary can be trusted
with thoughts and questions about life. According to
Mallon, confessional diaries are most often the prov-
ince of adolescents.
Q Prisoners: With nothing to do all day and all night,
prisoners often use diaries to pass the time.
Taking these types of diaries as the basic need for the Diary
program to fulfill, its basic entry window is shown in Figure
17-1.
If you wanted to make this program more specific, you could
force these fields to be dates. However, if you look back at the
types of diaries, you will see that this choice does not fit with
some of the requirements.
Alternatively, you might consider making these fields pre-
pared items in a pop-up menu; they might also carry edits
with them so that they are unique. Again, the overall scope of
this project argues for totally customizable titles and subtitles.
(However, these are all good projects for you to pursue to
learn more about programming for Mac OS X by modifying
Diary in these ways.)
Below those fields, another text field allows a
summary of the entry to be displayed. For creators, such a
summary might be the problem to be solved or the experi-
ment to be conducted. For others, it can be a literal summary,
a quote or phrase overheard, or anything brief and textual
that applies to the entry.
The summary field is longer than the title and subtitle in the
view shown in Figure 17-1. The larger field suggests that you
can enter more data. The fact that the field is not placed within
a scroller suggests to the user that only the visible amount of
data should be entered. (In fact, much more can be typed, but
it will be hard to see.) Gradually, you will learn how to use the
Aqua interface elements not just to show people what they
can do, but also to suggest to people what they should not
do--enter long summaries.
Image To the left of these three fields, an image field is avail-
able for graphics to be pasted or dragged into it.
The choice of a single image field suggests to a user that this
is primarily a text-based diary. Picture diaries are usually
called scrapbooks, and if you were designing one it would
look quite different. The image is subsidiary to the text, and
this program does not allow for editing. You can edit images
in any of a variety of programs.
If you want to modify Diary, you can add image editing fea-
tures to it.
Text The large scrolling text view in the center of the win-
dow allows Rich text to be entered (with formatting and
styles). This is the body of the entry, and it is essentially un-
limited.
Diary uses many features of the Aqua interface. For example,
there is a drawer that you can open as shown in Figure 17-2.
A drawer is a good interface element to use to let people have
easy access to information or controls that they sometimes
need. If you read Mallon's book, you will see that people fre-
quently annotate their diaries; they also often make contem-
poraneous notes that they later expand into full entries. Both
purposes ideally fit a drawer: an object that can be there if
needed and closed up if not needed.
Toolbars are another important new feature of the Aqua inter-
face. They are appropriate for icon-driven commands that
you may need close at hand (or not, if you close the toolbar).
Because a toolbar may not always be open (and because users
m a y not know h o w to do so), it is important that all toolbar
commands also appear in the menu bar. However, while the
commands in the menu bar may be scattered among a variety
of menus, in the toolbar, they are all equally available. The Di-
ary toolbar is shown in Figure 17-3.
The w i n d o w s in the previous figures have shown a single Di-
ary entry. Obviously, a diary contains m a n y entries. The data
structure used in Diary is not uncommon. In fact, it is very
similar to (indeed, borrowed from) the data structure in
Sketch, a Cocoa example.
A Diary document contains two types of data:
0 Diary Data. This data consists of the Diary name and
the name of its owner. There is one set of Diary data
per Diary document (i.e., one owner and title).
0 Diary Entries. Within the Diary, a variety of e n t r i e s ~
each in the format of the windows shown in these fig-
u r e s ~ a r e stored. At run time, these entries are placed
in an array in the Diary Data. Any number of entries
can exist, but there is only one entries array.
If you create a document-based Cocoa application in Project
Builder, a document object~MyDocument~is automatically
created for you. In the Diary program, you will see that two
other classes are created: DiaryData and DiaryEntry. They
correspond to the two types of data described here.
In developing a document-based application, you always
have to consider where the data will live. In the TextEdit ex-
ample, it lives within the document itself; in Sketch and Diary,
it lives primarily outside the document object in custom ob-
jects.
The Model-View-Controller paradigm comes into play here.
As noted previously, the classic MVC architecture omits doc-
uments and data storage. (NeXTSTEP and the original Open-
Step similarly omitted documents. The NSDocument class
became part of OpenStep only after Apple purchased NEXT.
The document-based computing paradigm was added in
1997.)
You can view your document as a controller, a model, or both.
There is an attraction in leaving the data (your model)
" p u r e " ~ t h a t is, untouched by any platform or framework
considerations. Such code can easily be ported from one envi-
ronment to another, with the visualization (view) and manip-
ulation (controller) code rewritten for whatever particular
environment it is in. In such a case, your document must be a
controller for the data. It must store and restore it. (Storing
and restoring is almost always platform- a n d / o r framework-
specific.)
On the other hand, you can take the stance that the data in the
model can manipulate itself as asked by the c o n t r o l l e r ~ a n d
that manipulation can include storing and retrieving it. Such
a choice means that the model data must know how to use the
framework's storage mechanisms; as a result, it is no longer
platform- or framework-agnostic.
The choice made in Sketch (and in Diary) is to make the doc-
ument more of a controller than a model. In both cases, it asks
the data to store itself, and the data uses Cocoa calls to do so.
In TextEdit, the document itself contains the data; there is no
choice to be made, as model and controller are one object.
Yet a third architecture can be used: You can make the docu-
ment a controller and yet keep the model pure by having the
data objects call routines in the controller, which then interact
with the platform or framework. This is a more complex struc-
ture, but it does keep the i n p u t / o u t p u t routines out of the
data model.
Each of these architectures is justified, and each has been used
both in demonstrations and in production software. Some of
the choices are a matter of flipping a coin; others are influ-
enced by whether you are writing for multiple frameworks or
classes. The architecture used in Diary and Sketch seems to
strike a h a p p y medium: It is highly structured, yet it is not so
complicated that it cannot be modified and maintained. It also
avoids a problem that the all-in-one approach of TextEdit
sometimes has: By mixing model and controller functionality,
you can lose sight of which is which and it can be more diffi-
cult to modify the software. (As an exercise, try to find where
the data in TextEdit is stored.)
Thus, in Diary, you will find that the document object has a
reference to a single DiaryData object; in turn, that object has
an array of DiaryEntry objects. As you will see in Chapter 18,
this structure requires that the entire data structure be initial-
ized when a new empty document is opened: A DiaryData
object with an array of one DiaryEntry is created.
In both Java and Objective-C, there are three primary classes
in Diary. They are described throughout this part of the book,
but this walk-through shows you what they are and what
their primary methods are.
The classes are:
1. DiaryDocument--the document
0 DiaryData--the contents of the diary as a whole, in-
cluding a list of entries
3. DiaryEntry--each of the entries within DiaryData
Here are the major sets of methods in these classes. Methods
within them are described throughout this part of the book.
(Not all methods are listed here.)
DiaryDocument is the main document; it is the File's Owner
object in Interface Builder, and it is the object for which ac-
tions and outlets are exposed in Interface Builder.
Objective-C and Java routines you would expect.
Builder document window is loaded at run time, win-
ation, which is where most interface elements are initialized
and fields are set.
A critical role of docu-
ments is to manage changes, updates, and dirtiness so that
documents are saved w h e n needed and the display is re-
d r a w n w h e n appropriate. Methods such as i s D o c u m e n t -
do this.
The objects in the document and its
subsidiary objects need to be flattened into a form that can be
written to disk: m o v e F i e 1 d s T o D i a r y D a t a moves data from
the interface elements into data objects, and then c r e a t e -
DiaryDictionary and diaryDocumentData provide a
data object to be written out by d a t a R e p r e s e n t a t i o n -
Persistance(Retrieval) In the other direction, l oadDa-
taRepresentation reads data and passes it on to d i a r y -
Three toolbar delegate methods are implemented to
Following are the sets of methods for the main data model
class, DiaryData.
As in DiaryDocu-
ment (and most other objects), these are the methods you
would expect.
These methods set and get data from the object's
variables. Note that this application structure places changers
and managers of document dirtiness at the highest level;
some Apple document architectures place changers at the
lowest (model) level.
These methods are called by the actions from
the document. They are not Interface Builder actions them-
selves (which are in DiaryDocument), but rather methods
Within the DiaryData object, a set of individual DiaryEntry
objects is created. Following are the primary methods for that
class.
These, too, are the
methods you would expect.
These methods get and set instance variables. The
note in the previous section about changers applies here, too.
method creates a new dictionary object and populates it with
this entry's data. Each DataEntry object generates its own dic-
tionary; all of these dictionaries are consolidated into a Diary-
wide dictionary.
From the DiaryData
Dictionary method, the static (Java) or class (Objective-C)
The application object in Cocoa runs everything. You rarely
override the default application class. Whether you are writ-
ing in Java or Objective-C, main.m is the same:
A global NSApplication object (called NSApp) is created and
run. In addition, the main nib file is loaded. As you saw in
Part II, this allows an application to be launched and to exe-
cute if it uses nothing but the standard Cocoa objects (and you
can do quite a lot with just them). However, if you need to
perform computations or calculations, or if you need to store
and retrieve data, you will need to implement your own cus-
tom classes. If a nib file encounters a customized object~such
as a view or an override of N S D o c u m e n t ~ t h e appropriate ob-
jects are instantiated using the code that you have written,
and action methods are called as needed based on the inter-
face activity.
What this means is that if you want any code that you have
written to execute after the launch, it must be sparked by a
custom object's activity (and that activity can be no more than
its display in a w i n d o w that was opened from the main nib
file).
Unlike in some other frameworks (such as MacApp), you do
not override the basic application object. You have your code
invoked by attaching it to an object that is displayed in the
first w i n d o w that opens. This is not nearly so complicated as
it may s o u n d ~ i t is rather obvious. It is a very rare case in
which you want to execute code in the context of a graphical
user interface without some visible manifestation of that code.
If someone opens a document from within your application
(or drags a document onto the application icon), the user ex-
pects a w i n d o w to appear. Sure enough, Cocoa creates a doc-
ument, opens a window, and links the two if you are using the
basic template from Project Builder. Doing something auto-
matically behind the user's back and without a w i n d o w to re-
port on the activity violates most user interface guidelines.
Some programmers do feel the need to manipulate the appli-
cation object. In Cocoa, the w a y to do that is to attach a dele-
gate to the NSApp object. Like behaviors in MacApp,
delegates get a chance to respond to events or messages that
are sent to the primary object; any of the delegated methods
can be called from your custom object. Unlike with some Co-
coa delegates, you can implement as many or as few of the
NSApplication delegate interface methods as you want. Con-
struct a descendant of NSObject (that is, any Cocoa object),
and implement whatever you want. Then attach that object to
NSApp in Interface Builder. Alternatively, you can use the
following code.
In Java:
In Objective-C:
The NSApplication delegation methods are shown in Table
17-1. As you can see, they focus on being able to instruct the
application (through its delegate) to automatically open or
print files, to indicate if it should open files in response to a
user request, and to terminate. There is not much else that the
application object can do that you should want to influence.
Of course, you can call methods of N S A p p at any time if you
want to do so. Normally, you do not do so except to get refer-
ences to a key w i n d o w or other global entity. Even in those
cases, you normally work with more general methods, as you
will see later in this book.
Delegates get a chance to respond to messages sent to the ap-
plication object (or, if you prefer the terminology, they can re-
spond to calls on the application object's methods). The Cocoa
notification system fills in the other side of the process: It al-
lows the application object to communicate outwards to ob-
jects that have registered as wanting to be notified about
events. (The notification system is described more fully in
"Notification" starting on page 404.)
Delegation and notification remove most of the legitimate rea-
sons for overriding NSApplication; the messages and meth-
ods that cannot be accessed through those structures should
very rarely be overridden. NSApplication methods can be ac-
cessed directly by using the global NSApp object. They are
not overridden, and the most frequently used methods are
those that return shared objects. However, remember that you
are likely to be able to get access to those objects (windows, for
example), through objects such as w i n d o w controllers that au-
tomatically are attached to your document.
The NSApplication notifications are shown in Table 17-2.
Their names are generally self-explanatory; more details are
available in the Cocoa electronic documentation both online
and on the CD-ROM. As you can see, these notifications are
sent primarily w h e n the application is being hidden or unhid-
den, launched, or terminated. There also is a notification that
is sent w h e n the screen parameters change. In general, these
notifications are needed for you to be able to update w i n d o w s
that need to be changed to reflect environmental changes
rather than user actions. (One attractive feature of the notifi-
cation system is that if you do need to know w h e n one of these
events has taken place, you no longer need to search in the
framework code to see which application method is called at
that time and how to override it. Even if future releases of the
framework move processing from one method to another, the
notifications will still be generated.)
You may need to modify legacy MacApp applications or
adapt them to Cocoa or Carbon. MacApp handles application
objects differently from Cocoa. Also, you may be called upon
to handle non-framework applications from legacy applica-
tions. There, too, the application structure is different.
In the Nothing example, the smallest subclass of TApplication
is created: a constructor, a destructor, and an override of mo-
MakeDocument that creates the document (and thence the
window).
In main, a small section of code creates the customized
TNothingApplication object and then runs it ( I n i tUMacApp
initializes MacApp itself).
The C++ constructor is called w h e n the o~ect is created:
This constructor relies on templates to create the view for the
Nothing example. In practice, you can either do that or pro-
grammatically create a view by overriding TDocument. Do-
MakeViews w h e n you override TDocument for your own
document. In some cases, both practices are followed.
The destructor is empty, but the D o M a k e D o c u m e n t override
is not:
You must override DoMakeDocument to create a document
for your application. In this case, a standard TDocument is
created; in almost all other cases, you create your own docu-
m e n t - s o m e t h i n g like a TMyDocument. (Remember that this
example focuses on the smallest possible MacApp program,
not the most useful one!)
Compared to Cocoa, these differences emerge"
Q Always subclass the application object (TApplication)
in MacApp; rarely, if ever, do so in Cocoa.
0 Standard objects such as windows and views are cre-
ated automatically from your nib file in Cocoa (the nib
file is almost always built in Interface Builder). In
MacApp, they are created programmatically (in over-
rides of T D o c u m e n t . D o M a k e V i e w s ) or from tem-
plates.
0 As you have subclassed TApplication, it is easy to
override any of its methods to gain access to the appli-
cation at critical points; with Cocoa, do so with delega-
tion and notification.
Applications built without frameworks have yet another
structure--in fact, two of them. The typical m a i n function
does some initialization; it then contains the main event loop
or it calls a function that runs the event loop. In the older ar-
chitecture, this is based on wai t N e x t E v e n t . In the Carbon
direct-dispatch structure it is done differently. The Carbon di-
rect-dispatch structure was described in "Direct Dispatching
with Carbon Events" starting on page 157.
It is unlikely that you will be writing a new application from
scratch that uses the old style of event dispatching (wai t -
NextEvenr But it is quite possible that you will have to read
or modify legacy applications, and for that reason you need to
know how events were handled in them. Here is main from
the NetSprocketsTest example that you can download from
the Apple Developer site:
The function (underlined) is called and remains
in an infinite loop until the user quits as you can see here:
The underlined function does the actual dispatching; its be-
ginning is shown here:
This example was written in 1996. Note how the amount of
application-handling code you need to write has decreased
from that time--first with the MacApp framework and then
with Cocoa (where you do not have to write any such code).
The structure of the application that is shown here is fairly
standard for older non-framework Macintosh applications.
Thus, if you need to modify or convert such a program, go im-
mediately to ma i n, find the event loop (or the call of the event
loop function), and track down the event-dispatching code.
Much of it will be handled by the framework (MacApp or Co-
coa), because most of it is involved with moving windows,
manipulating menus, and the like. Search out the application-
specific code, and you will see what you need to modify or
convert to Cocoa.
This chapter has provided an architectural overview of appli-
c a t i o n s - b o t h in Cocoa and in Carbon (for MacApp and for
non-framework applications). It also has shown you the struc-
ture of the Diary application and of its data--this example
will be used extensively throughout this part of the book.
This overview sets the stage for the remaining chapters in this
part of the book. You need to know what the application ob-
ject can do for you, but now you need to see what tools are
available for it to use. Then, you can come back and imple-
ment the application properly.
From the overview of the application, the next chapter focuses
on the smallest units: the building blocks and data elements
that you use.
This Page Intentionally Left Blank
From the large architectural and application overview of the previ-
ous chapter, this chapter moves to the lowest level: the building
blocks and basic types of Cocoa and Carbon. It starts by outlining
the steps you can take to create a data strategy and ways that you
can use this strategy to help you build a prototype and then progres-
sively more complete versions of your application.
Next, you will find an introduction to the basic types of Mac OS X,
along with information about how to create them programmatically.
(There are significant differences between Cocoa and Carbon as well
as between Java and Objective-C.)
Among the most useful building blocks of Mac OS X are collec-
tions~arrays, dictionaries, and sets. These can be immutable (that
is, they are of fixed size and contents), or they can be mutable. All
are described here.
Property lists provide a convenient way of storing information; they
work together with XML to manage information without your need-
ing to worry about formats and field widths. They are implemented
using the dictionaries described in this chapter.
Preferences (Carbon) and defaults (Cocoa) pull together even more
of these technologies to help you provide customization for specific
applications, specific users, and specific computer environments.
A section showing you how to create objects in Objective-C and Java
concludes the chapter.
Data modeling, data strategy, and normalization are all terms
that refer to the same basic concept: creating a coherent view
of the data in your project. As noted Chapter 17, the first and
most crucial step is understanding the data you must deal
with.
Experienced developers do not just take a user's w o r d as to
what the data is: They look at samples of the data. Look for
patterns, and look for anomalies. If something seems wrong,
it m a y be a legacy of an old s y s t e m ~ o r it m a y be that you or
the user does not fully understand the data.
Once you feel comfortable with the data, you need to develop
and implement your data strategy. Three steps are key to this
process"
1. Factoring data and interface elements
2. Fishing data through the objects
3. Implementing the strategy
Whether or not you use the model-view-controller paradigm
as your guide, it is important to separate interface elements
from data elements. The consequence of this is that your code
can be transported from one platform or framework to anoth-
er; it also means that you can incorporate external code (in C
or another language) easily. Keep a solid wall between the
customizations of your environment and the substantial real-
ity of the data.
When you use Interface Builder, it is easy to create a simple
application as well as interfaces to even complex ones. As you
saw in "Outlets" on page 115, it is easy to connect interface el-
ements to fields in your customized code. You can then write
that code to use the data accordingly.
However, remember that Interface Builder lets you connect to
the interface elements. Although you can use them to store
data (and, in fact, they must store data at least temporarily to
display it), for most applications, you need to move the data
from the interface elements into local variables (fields of your
objects).
Here, for example, is code that does the following:
1. Declares a text field in an object
2. Declares a data field in that object
3. Sets the text field to the data field's value
0 Retrieves its v a l u e ~ w h i c h m a y have been changed by
the user
This code is based on the Diary code. It is simplified, and in-
tervening lines have been removed.
Here is the Java code"
Here is the same code in Objective-C:
At this degree of simplicity, there is no substantive difference
between having a separate variable (_no t es) and using the
text field ( n o t e s F i e l d ) to store the data: After all, you can al-
ways use the s t r i n g message/function to retrieve that data.
But remember that if you want to separate the interface ele-
ments from the substantive elements, you want to keep ob-
jects such as the text view out of the model.
A simple (and very common) example of w h y this is useful
occurs w h e n you change the type of the interface element.
You can place a string in a text field or a text view (the text
view scrolls and is suitable for longer text). If you write your
code using a string variable such as _no t e s , it is a trivial mat-
ter to change the interface element; however, if you carry the
text field or the text view into your calculations, you will need
to make adjustments. In particular, although text fields re-
spond to the s t r i n g V a l u e message/function, text views do
not: You must use s t r i n g instead.
Even more important is the case in which your interface ele-
ments must represent different data at different times. In the
Diary example, for instance, the window contains the data for
whatever diary entry is current. Users can click the Next and
Previous buttons to move back and forth in the diary. As they
do, the data for the then-current entry is placed into the inter-
face elements. If the data itself is stored in the interface ele-
ments, you could have only one set of data displayed. (You
could, of course, have multiple copies of the interface ele-
ments and move them into and out of the display window,
but this would be awkward, inefficient, and slow. You will
find some programs that do this, but it is a poor choice.)
The name of the actual data field starts with an underscore.
Any such convention is good (this one is particularly com-
mon). It reminds programmers that this is private, internal
data that should normally be accessed through an accessor--
as the next section shows you.
Accessors let objects set or retrieve
data without the programmer having to worry about how it is
stored. Here, the third and fourth lines in the previous exam-
ple are rewritten using accessors.
Java:
//3
//4
Objective-C:
Java:
Objective-C"
One issue that arises with the use of accessors is that of dirty-
ing the underlying d o c u m e n t - - t h a t is, requiring it to be saved
w h e n it is closed. If accessors dirty a document, they cannot
be used for setting values that do not dirty the document,
such as w h e n an existing document is reread from disk and its
values need to be set to the s t o r e d ~ u n d i r t i e d ~ d a t a .
A good w a y around this issue is to use accessors only to access
data and changers (or whatever you want to call them) to
dirty the document and call the accessor.
these accessors with the DiaryData and DiaryEntry ob-
jects described in Chapter 17, you get the actual code that is
used in Diary, as you can see in the following code snippets.
The accessors just shown become methods of a subsidiary ob-
ject instance of DataDiary in this step), and
the data element itself (_no t e s) is declared there:
Java:
//4
Objective-C:
This may seem like a lot of effort, but in practice it is simple.
You will quickly get used to accessors if you are not used to
them now. Your code will be more stable and maintainable,
and it will be easy for you to develop prototypes quickly.
The process of using accessors in this way is like that of fish-
ing a cable through a wall or behind furniture: Its course may
be serpentine, but the end result is well crafted.
In fact, the sequence of steps in the previous section provide a
roadmap to quick and accurate software development. If you
know that you will be structuring your data in this way, you
can start by declaring the data elements in your most basic
class (your MyDocument object in most cases). This is the
wrong place for them, but you know that you will move them.
Create accessors in that class that access the data element by
n a m e - - a s in _ n o t e s = t h e N o t e s . Except for the references
within these accessors, never use the variables directly. In-
stead, use your accessors. This will allow you to prototype the
interface using Interface Builder. You may finish the interface,
but more likely you and your users will take some time to
work with it, tweak it, and experiment with using it.
Meanwhile, implement the next portion of your data strategy.
In Diary, that involved creating both the DiaryData and the
DiaryEntry objects. Create a DiaryData object when your doc-
ument is initialized, and then place the declarations of these
variables in that object (remembering to remove them from
the document object). In addition to the declarations, create
accessors in the subsidiary object. Then, change the code in
your document to use the accessors rather than the variables
directly. That means changing
Once you have done that, your document object is free of the
knowledge of the variables that you temporarily inserted in it
(and your prototype should still work).
Of course, the DiaryDocument object contains a DiaryEntry
object, which is where the actual _no t es field should live.
Follow the same process again. Create a DiaryEntry object
w h e n you initialize the DiaryData object. Declare _ n o t e s
there, and write accessors for it. Then, in DiaryData, remove
the direct references to _no t e s and replace them with calls to
the DiaryEntry object's accessors.
In DiaryDocument, you will have this code:
In DiaryData, you will have the following:
You are not done yet--the DiaryData object still contains a
number of DiaryEntry objects. Use the same process to con-
vert a local variable (theDi aryEn try) to use an accessor. The
accessor you will create in DiaryData returns one DiaryEntry
object--the current one. (How that is determined will be de-
scribed elsewhere.)
You can thus rewrite the two lines of code as follows"
You gradually move the actual variable declarations deeper
and deeper into your data structure. As you do so, the acces-
sors change in the same w a y at each level:
0 They start out in the document class accessing the
variable ( _ n o t e s ) directly; that variable is also de-
clared there.
0 You move the variable down one level, and you change
the accessor to call an accessor at the lower level.
You continue this process until the data elements are located
where they belong.
The use of accessors is normally presented as a way of making
your code "pure" and implementing architectures such as
model-view-controller. In practice, you can use accessors as
shown here to help get an early version of your code up and
running quickly.
Armed with a data strategy and your accessor-based design,
you are ready to actually declare and use variables. Mac OS X
provides a number of basic types in both the Cocoa and Car-
bon environments.
You may be used to writing code and using the types of Java
and the C languages directly. You will find that the types de-
clared in the Foundation framework (Cocoa) and in the Core
Foundation (Carbon) are more powerful than the raw types.
Specifically, you will find that these objects provide you with
the ability to read and write them, compare them, and trans-
form them without writing much of the code once had to
write.
The very simplest types~integers and booleans~are not
wrapped in these foundation classes. All other basic types are.
In addition to the simple data types described in the previous
section, Mac OS X provides a number of more sophisticated
tools. These range from the collections, property lists, and
preferences described in the remaining sections of this chap-
ter to data types and objects that are designed for specific pur-
poses (such as visualization). The latter types and objects are
described later in this part of the book.
Collections let you handle groups of objects as a single entity.
Traditional programming structures let you handle a basic
collection~arrays. Dictionaries provide a powerful feature of
Cocoa and of Carbon: You can place entries into them and
identify each entry with a key. Unlike the ordered, numeric
keys of arrays, keys of dictionaries are strings and are not or-
dered. Finally, sets let you place entries into an unordered, un-
keyed set--just like a mathematical or logical set (in fact,
exactly like such a set).
Arrays are based on the NSArray class; they function just as
arrays do in standard programming languages. However,
they provide a number of additional features:
The method returns true if an ob-
ject is in the a r r a y - - y o u do not have to iterate through
and test each element until you find a match.
Given an object, i n d e x 0 f 0 b j e c t returns its index in
the array (a RangeException is thrown if the object is
not in the array). Again, this saves you writing itera-
tion code.
If you do need to iterate through an array, you can use
m e r a t o r ) method to return an enumerator (in Java or
Objective-C).
As you might expect, a c o u n t method returns the
number of elements in the array.
Arrays provide ordered and numbered access to collections of
objects; dictionaries use keys. Each key is a value that can be
hashed (usually a string), and it is paired with any object that
you want. Like arrays, dictionaries can contain dissimilar ob-
jects, provided that they all descend from a basic object (such
as NSObject in Objective-C or Object in Java).
Dictionaries provide some functionality similar to that of ar-
rays in these commonly used methods:
9 The c o u n t method returns the number of k e y / v a l u e
pairs in the dictionary.
9 Given a string containing a key, ob j e c t F o rKey re-
turns the appropriate object (if it exists).
Dictionaries are useful for storing large and small amounts of
data. As Sketch (and Diary) demonstrate, they are particularly
useful for storing a handful of data values for objects in an ap-
plication. Rather than worry about formatting or tagging data
to identify it, you can simply store an object's data in a dictio-
nary. The entire dictionary can be converted to a property list
(see "Property Lists" on page 384) and the property list, in
turn, can easily be stored on and retrieved from disk. Each of
the objects in your application has its own dictionary.
Here is h o w Diary unloads data from a dictionary (it is mod-
eled on Sketch). There are three steps involved:
0 Create constants for the dictionary keys (that is, con-
stants to identify the data you will store).
2. Declare your local variables.
3. Unload the dictionary.
your dictionary entries in your program. In fact, it is a good
idea to do so. In Java, place them at the top of your Java class
file like this"
In Objective-C, you can define these constants at the top of
your .m file (not the .h header file)" that is because they are to-
tally private and no other part of the application should know
about them.
Other key constants are declared in Diary in the same way as
these.
Although they are not part of dictio-
nary maintenance, you will need local variables into which to
unload the dictionary. Following are the declarations from
Diary.
Java:
Objective-C:
When you have read
the dictionary in from storage, you can unload it into your lo-
cal variables. The following code snippets show you how you
can do that. There are two issues that you should note in par-
ticular:
0 This code does not use accessors; it refers directly to
the local variables. Some people prefer not to use ac-
cessors for this low-level initialization of variables;
others use accessors in all c a s e s ~ b o t h for low-level
initialization as well as for data entry and ongoing
changes during run time.
0 The variables that represent simple data types such as
strings are set directly. This dictionary (like that of
Sketch) contains an image. For such objects, you need
to declare a local variable such as o b j, test to see that
it exists, and then set it. If you do not do so, you may
wind up passing a null object to the
method that does the unarchiving. (For more on ar-
chiving, see "Archiving" starting on page 475.)
Java:
9
Objective-C:
In addition to arrays and dictionaries, sets provide unor-
dered, unidentified collections of objects. They, too, have the
common methods you would expect:
9 You can count the number of elements in a set with
To manipulate the elements of a set, you may want to
use a 110b j e c t s, which returns the set as an array.
One of the most basic set operations is determining
whether an object is a member of a set; c o n t a i n s O b -
j e c t does this.
Each of the objects described here is immutable in its basic
form. That is, you can initialize it from a file, array, or other
data structure, but you can then neither add to it nor remove
items from it. In both Cocoa and Carbon, companions to
NSArray, NSDictionary, and NSSet let you modify them; they
are n a m e d NSMutableArray, NSMutableDictionary, and NS-
MutableSet.
When you are reading data from a file, you may build a mu-
table collection. However, once you are finished reading, you
can pass it along as an immutable object for other purposes. In
addition, if you are repeatedly storing data into a collection,
you obviously need to make it mutable.
Here is the other side of the dictionary unloading process just
described: the code in Diary that loads a dictionary prior to
writing it out. First, a new mutable dictionary is created; then
the various data fields are stored with the declared keys. Note
the special treatment of the i m a g e object.
Objective-C:
Property lists use XML to store pairs of property names and
values. They are used pervasively in Mac OS X. Property lists
with their property n a m e / v a l u e pairs are similar to dictionar-
ies. In fact, it is simple to convert a property list to a dictio-
nary, and vice versa. On disk, a property list is often an
editable XML text file; w h e n you access it from a program, it
is a standard NSDictionary.
You can use property lists to store dates, numbers, booleans,
and strings. In addition, NSData or CFData types can be
stored in them. Most importantly, arrays and dictionaries that
contain those types can also be stored in property lists.
The diaryDocumentData method in the DiaryDocument class
stores a dictionary into a property list which is then written
out to disk (this is based on Sketch). Objective-C and Java dif-
fer in their handling of this process. In each case, the under-
lined code does the actual conversion from a dictionary to a
string containing a property list.
In Objective-C, you can convert a dictionary into a property
list by simply calling its description method"
The process is a little more complex in Java. The first line calls
a method that contains code like that seen previously in this
chapter: It creates a dictionary and stores objects into it using
the data in local variables and the predefined keys. Next, a
string property list is created from that dictionary. The re-
maining code (starting with NSMutableStringReference) is
used to optimize Java bridge performance.
On the opposite side, you can convert a string containing a
property list into a dictionary. In Diary, the diaryDictionary-
FromData method does this. It takes a data value as a param-
eter, converts it to a string, and then loads it into a dictionary.
The underlined code does the actual conversion from the
string containing the property list to the dictionary.
Java:
Objective-C:
Mac OS X uses property lists to store preferences and defaults
for applications as well as to store information about them.
The Core Foundation framework implements preferences
and defaults; they are available both for Carbon and Cocoa
applications.
Five domains are used for defaults. When an application is
searching for a default value, each of these domains is
searched in turn.
This domain contains values that can be entered
on the command line in Terminal. They apply to the single ex-
ecution of an application that is being invoked at that time.
Application An application can store its own default values
and preferences. This domain is specific not only to an indi-
vidual user. This information is stored in ~/Library/Prefer-
ences in each user's home directory.
GlobalDomain This domain contains global settings for each
user. Such settings can include units of measurement as well
as preferred languages (and their order of preference).
Languages In the languages domain, preferences for each
language are stored. A user may specify (in the global do-
main) what language should be used at the moment; any
number of languages may contain preferences that come into
play if the user changes the language preference in the global
domain.
Registration Preferences are set at the registration domain.
This is created when an application is installed, and it is spe-
cific to the computer (not the user).
A variety of preference key names are predefined for your
used. They include names such as CurrencySymbol (to speci-
fy $, s or u among other choices. Note that CurrencySymbol
is independent of language settings. English speakers may
well refer to yen (u just as Spanish speakers may refer to
pounds (s
A variety of date and time constants are available. Keys such
as ThisDayDesignations (which let you specify the string to be
used as the current d a y ~ " t o d a y , " by default) let your appli-
cation take advantage of a user's preferences.
You can set preferences at any time that you want. Normally,
you do so either when the user clicks OK in a preferences di-
alog or when some information that you know should be
saved is modified. (Sometimes the two interact, as when the
preference is to save passwords, window locations, and so
forth.)
Following is the code to save a
preference that consists of a number or object. These snippets
assume the following:
9 k e y is a string constant that names the preference
9 v a l is an object that contains the preference
9 1 o n g K e y is a string that names a second value w h i c h
contains...
9 1 o n g v a l , a long value (not an object) that contains a
second preference
In Carbon, you must pass your application's name (in the con-
stant in to the
already set up properly.
Cocoa/Java:
Cocoa/Objective-C:
Carbon:
As you might surmise, other similarly named methods let you
save integers, floats, and the like.
The actual saving of preferences occurs when the S y n c h r o -
n i z e method is called. In Cocoa, it is called for you automat-
ically in most cases. In Carbon, you need to call it explicitly as
shown in this code.
It is very common to want to save
w i n d o w positions. A method of NSWindow lets you do so au-
tomatically. It makes its own calls to the preferences manager
automatically whenever a w i n d o w is moved.
Java:
Objective-C:
Pass the name of the w i n d o w into the method, and Cocoa will
take care of everything for you. The w i n d o w name must be
unique; otherwise there is no way of keeping preferences
straight.
Having saved preferences, you need to retrieve them. Follow-
ing is the code to do so in both Java and Objective-C. If you are
saving default data, one useful place to insert this code is in
Cocoa/Java:
Cocoa / Objective-C"
Carbon:
There are some important differences between Java and Ob-
jective-C relating to the way in which objects are created. The
code snippets in this section demonstrate some of them.
The snippets also demonstrate a programming style that you
may or may not want to emulate. Some programming lan-
guages (such as Java and Objective-C) initialize variables to
appropriate defaults~usually 0 or null/nil. Other program-
ming variables leave uninitialized variables just like t h a t ~
with no value. This is one of those topics that can raise a fierce
argument among programmers. On one side is the position
that it is wrong--morally wrong--for a compiler or operating
system to interfere in any way with a programmer's code (and
that includes setting default values). On the other side is the
argument that the compiler or operating system should try to
catch errors or clean up code (such as mistakes that arise from
uninitialized variables).
Regardless of which side of the argument you take (if any),
you may want to initialize your variables as shown here. As
9
you can see, in most cases, they are initialized to neutral but
nonzero values (such as "entry title"). This means that w h e n
you are d e b u g g i n g your code, you can use the d e b u g g e r to
check the values of variables and watch as they change from
0 (which the compiler and operating system set) to your de-
fault value (such as the values here) and then to a real value.
In practice, as soon as this m e t h o d is called to initialize a diary
entry object, the default values are overridden with actual da-
ta.
A constructor in Java m u s t
start with a call to s u p e r ~ t h e constructor of its ancestor (this
is m a r k e d as 1 in the Java snippet). In Objective-C, the i n i t
m e t h o d m u s t start with a call to [ s u p e r i n i t ] which does
the same sort of thing. Note that { s u p e r i n i r returns an
object which is stored in s e x f; the Java constructor does not
return a value.
Creating Objects Simple variables are set with replacement
statements as is the case for _ZD, _ t i t 1 e, and so forth. Vari-
ables that are references to objects need to have objects created
for them. _ e n t r y , which is an NSData object, falls into this
category (underlined in both snippets). In Java, you create a
n e w object by calling its constructor; the constructor may
have parameters o r ~ a s is the case h e r e ~ m a y not.
In Objective-C, there is a s o m e w h a t more complex mecha-
nism for creating objects as s h o w n in this line of code:
Remember to read from the innermost brackets outwards.
This code does the following:
0 It calls a Class object (NSData) to allocate an instance
of itself.
2. It then calls the instance's i n i t method.
In practice, you reuse this line of code over and over: All that
you change is the name of the class that you are instantiating
(NSData in this case). Note that in some cases, you call object-
specific i n i t methods such as the i n i t w i t h F r a m e method
of NSView.
You create objects--such as the
_ e n t r y objects--when you know you will need to refer to
them. In other cases, objects are created on demand. In Diary
entries, for example, images can be supplied by the user.
Thus, the _ i m a g e object is left as null until the user places an
image into the entry.
It is possible for the user not to enter any data into the _ e n t r y
object; in that case, the expense of creating that object and
storing it goes for naught. In practice, though, that is a rare oc-
currence. This is an example that illustrates h o w knowing
your application and its data (and h o w people deal with
them) can help you to write more efficient code.
Java"
Objective-C:
For most applications, the structure of the data elements and
their basic manipulation lie at the core of the design. This
chapter has shown you the basics of modeling data, using ba-
sic objects, and using the powerful collection classes available
in both Cocoa and Carbon such as dictionaries. Property lists
and preferences are implemented using these tools, and they,
too, are your basic building blocks for applications.
With them, you can move on to implementing your applica-
tion. The next chapter focuses on the events and actions that
drive its processing.
This Page Intentionally Left Blank
Delegates, and
Notification
Having dealt with the big picture (applications) and the smallest
building blocks, it is time to turn to how they work together. This
chapter examines how the application and its objects animate those
building blocks and the more complex objects that you create in your
applications.
The most basic concept in this chapter is that of events~they cause
the application to take some action. Sometimes they are initiated by
users (mouse clicks, for example), and other times they are generated
by the application itself. (They also can arrive from the operating
system or from other applications.)
Objects in your application respond to events. Called responders,
they include views, buttons, and other interface elements.
Delegates provide a way for an application and its objects to pass
events along to other interested objects.
The notification system in Cocoa does just what its name implies:
It allows one object to automatically notify others (which it may not
even know about) when something has happened.
Note that a number of the concepts in this chapter are required to im-
plement toolbars. The complete code for implementing toolbars is
given in Chapter 20; see "Implementing Toolbars" on page 440.
In all graphical user interface frameworks, events provide a
mechanism for managing the event loop and for letting the
application and its objects know when something needs to be
done. Events always are a request for an application to do
something if it deems it appropriate. The application may de-
cide not to process an event, but it is always a request for ac-
tion in the sense that if the application does in fact respond to
an event, that is not incorrect. Events are not informational:
They may trigger actions.
There are two types of events:
0 Basic, system-level events include mouse clicks, acti-
vation of an application, menu selection, and key-
board events. Implementations of events normally call
the inherited method.
0 Action events are defined within your application.
They include higher-level concepts such as saving a
document, resizing an image, and finding or replacing
text. Implementations of actions may or may not (of-
ten not) call the inherited method.
9
Basic Events These are k n o w n and defined both in Carbon
and in Cocoa. Basic framework objects such as w i n d o w s con-
tain code to handle these events where appropriate. Thus, you
can rest assured that w h e n you create a w i n d o w in Interface
Builder, it will be activated w h e n you click it, and its resize
box (if you enable it) will work properly. (In Classic applica-
tions written without a framework such as MacApp or Pow-
erPlant, you had to actually write the resizing code!)
If you create a new interface element and subclass a standard
class (such as a window), all of these events will be handled
for you automatically. The one issue that you need to address
is that of overriding a basic method (such as m o u s e U p or k e y -
Down). If you do so, you must call the inherited method so that
if you do not handle the event it is properly passed on. The
purpose of the responder chain is to allow each object in turn
to have a chance to handle an event until one of them does so.
If you do not pass the event on, you break the chain and the
application becomes unresponsive.
Action Events These are your application-specific events (ac-
tions in Interface Builder). When they arrive at one of your ob-
jects, you must handle them there; you m a y pass them on to
other objects, but you do not pass them on to the default ob-
jects in Cocoa since they will not know about your own
events.
In Cocoa, events are objects--descendants of NSEvent. In
Carbon, as in the Classic environment, events are packaged as
data structures. Unlike events in the first Macintosh versions,
events in Carbon are now pointers to opaque structures; that
means that you cannot access fields within the pointer. An
event is passed around the system in a pointer of type Event-
You use accessors to get information out of the event objects
and data structures. For all practical purposes, you program
using the two types of events in much the same way when it
comes to getting data from the event.
The data in the event consists of general information such as
the time at which the event occurred as well as information
identifying the specific type of event (a mouse down, for ex-
ample) and data that applies only to that specific event (such
as a location).
Timers are a special type of event: They fire repeatedly ac-
cording to the parameters that you set. Each time an NSTimer
fires, an event of the type that you specify is sent.
Timers are part of the design that moves the event loop pro-
cessing from individual applications into the operating sys-
tem. In the old days, periodic events were handled by
individual applications. Each one kept track of when it need-
ed to perform tasks, and in the constantly repeating event
loops, such tasks were initiated as needed.
Using timers is much more efficient for the computer's total
environment. It also removes code from your application,
making it easier to maintain.
Most objects that respond to events are descendants of the
NSResponder abstract class. The abstract class has stubs for
many common actions that responder objects implement, but
because it is an abstract class, they are not full implementa-
tions. (See "Selectors" on page 401 for information on how to
deal with this situation.)
The abstract class implements the mechanism for building the
responder chain and for manipulating it. Thus, almost all ob-
jects that are in the responder chain are descendants of NSRe-
sponder.
Windows are critical players in the responder chain. Mouse
clicks and keystrokes go to the active w i n d o w (the key win-
dow) and to its responders; then, they go to an application's
main w i n d o w (if it is different from the key window). From
there, they are sent to the application itself.
At each stage of the process, an NSResponder can pass the
event off to a delegate (see "Delegates" on page 403). Once an
object handles an event, it is not propagated farther up the re-
sponder chain.
However, w h e n an object handles an event, it may pass that
event on to its superclass (or even to an entirely different ob-
ject). There are two chains of linked objects in play at that
time:
0 The responder chain is the linked list of objects that
will respond to any event that comes in.
0 An individual object's inheritance tree or other ad hoc
linked list of objects is the chain that will process a spe-
cific event.
In reality, you do not care at all about the responder chain,
with the exception of the first responder (the head of the
chain). Cocoa just manages everything for you. The first re-
sponder, though, may require your intervention.
You usually set the first re-
sponder using Interface Builder w h e n you design your win-
dows. However, there also are two general methods that you
can use to set the first responder. Both are methods of NSWin-
dow.
The first, is used dynamically to
make an object (usually a view in the window) become the
first responder at that moment. The second, s e t I n i t i a 1 -
F i r s t R e s p o n d e r , is used to set the first responder for the
w i n d o w in general.
Java:
Objective-C:
You rarely need to use these methods, as the default behavior
is intuitively correct in most cases. Furthermore, not only is it
correct, but changing it may also make the user confused.
(One case in which you may need to set the first responder is
w h e n you have a text entry view within a scroller.)
Far more common than
setting the first responder is specifying whether an object will
allow itself to become a first responder. By default, views re-
turn false w h e n their a c c e p t s F i r s t R e s p o n d e r function is
called. This means that unless you actively allow a view to be-
come a first responder (whenever it is called u p o n to do so), it
will not.
With Interface Builder, you can set this using the Enabled op-
tion on a control's Attributes pane in Show Info.
Periodically, it is necessary to refer to a method of an object or
to a procedure so that it can be manipulated as data. Objects
in the responder chain need to be able to provide information
as to whether or not they implement a given action that has
been requested (this is needed not only to carry it out but also
to preflight actions so that m e n u commands can be properly
enabled or disabled).
In other cases, a specific action needs to be attached to a tool-
bar item, to a notification, or to an undo stack.
In Carbon, Universal Procedure Pointers (UPPs) identify pro-
cedures in much the w a y that is needed. In Cocoa, two similar
mechanisms are used: one for Objective-C and the other for
Java.
A type, SEL, exists in Objective-C. A
method of NSObject lets you query whether the particular de-
scendant of NSObject you are interested in handles the mes-
sage.
In usage, you can check whether a n y O b j e c t responds to the
drawMe message:
You need to use selectors w h e n you are attaching actions to
dynamic objects. For example, if you are creating a toolbar
item, you set its action as follows:
Java Selectors Java does not have a SEL type. Instead, an NS-
Selector class is used to identify a method, and j a v a . 1 a n g .
r e f 1 e c t . Me t hod is used to determine if a class has a given
method. This is s o m e w h a t different from the r e s p o n d s -
To S e 1 e c t o r m e t h o d of NSObject in Objective-C, since in
Java the query reflects a given m e t h o d in a given class; in Ob-
jective-C, r e s p o n d s T o S e l e c t o r reflects only a given meth-
od in any class. Practically, this e n o r m o u s conceptual
difference does not matter in most of the w o r k that you do.
You construct an NSSelector using the m e t h o d n a m e and an
array of parameters for the given class. You can obtain these
by calling the class m e t h o d of the class; the array of p a r a m e t e r
types for NSNotification is {NSNotification.class}, that of NS-
View is {NSView.class} and so forth. Here is the code to create
a selector on the fly:
This creates a selector identifying the s t e p E n t r y m e t h o d of
the D i a r y D o c u m e n t class.
You can use this to set an action for a toolbar item in the fol-
lowing way:
Sometimes you need to set a n u m b e r of actions and need the
class p a r a m e t e r types repeatedly. You can store them in an ar-
ray and use that variable as follows:
Two methods let you send a specific selector to particular ob-
jects. Cocoa uses these methods internally, and you do not
have to worry about them in most cases.
The first is a method of NSApplication. You specify both the
target and sender; if the target is nil, the responder chain is
traversed.
You can ask any NSResponder to attempt to perform an ac-
tion; you pass into it the object that is the parameter of the ac-
tion method using its i d.
Many objects allow you to set a delegate for them; the dele-
gate implements certain methods that augment the primary
object's functionality. In many cases, this means that instead
of overriding the primary object you can attach a delegate to
it.
The easiest w a y to attach a delegate to an object is in Interface
Builder. Draw a connection (CONTROL-drag) from an object to
another one; attach the connection to the delegate outlet in the
Info window.
You may need to attach a delegate to an object programmati-
cally--again, toolbars require this. The toolbar object itself im-
plements only the most basic functionality. It requires a
delegate to tell it what the default items are, to identify the al-
lowable items, and to provide it with an NSToolbarItem for a
given identifier. In the Diary example shown in Chapter 20,
the document object (an override of NSDocument) is the del-
egate and implements these methods.
Sometimes, a delegate is required to implement some or all of
a set of methods. Other times, the delegate can pick and
choose. The documentation of an object's s e t D e l e g a t e
method will list the required methods for the delegate. If you
attempt to attach an inappropriate delegate to an object, an er-
ror message appears in the console window.
In Objective-C, when you set a delegate using s e t D e l e g a t e ,
the delegate object is not retained. You should call r e t a i n on
it (and later r e l e a s e it when the primary object is deallocat-
ed).
As objects within a single application (or several applications)
interact, their ability to notify one another of specific events
happening to specific objects makes for efficiencies both in
coding and in running applications. For example, many inter-
face elements reflect the states of the system and other appli-
cations (a font menu that contains the currently installed fonts
is one such case). Without a notification structure, whenever
you update your interface (redisplay your menus, redraw a
panel, etc.), you need to go out and find what the current state
is: have fonts been installed or uninstalled, has another appli-
cation started or stopped, etc.
Using notifications, you can check the state of the system and
other applications w h e n you first present your user interface
and register an interest in changes to those states. Then, in-
stead of checking the states each time you re-present your in-
terface, you can happily continue to display your initial states
until notified otherwise.
Of course, notifications can be used for many other purposes
than keeping your interface up to date; the example given
here just happens to be a common case.
Objects can communi-
cate with one another in various ways:
9 An object can obtain a reference to another object and
send messages to it, invoking its methods. This re-
quires that the first object have a reference to the sec-
ond and know what methods it has.
9 A less tightly coupled structure lets the first object
send messages to the second via an intermediary. The
intermediary object (often a delegate of the first object)
needs to know what messages the first object might
send and what messages to pass on to the second ob-
ject. The intermediary can function as a translator,
converting one API to another.
9 The least tightly coupled structure has no links be-
tween the objects. The first object posts notifications
about possibly interesting events that it has processed;
the second object responds to those notifications for
those objects in which it is interested.
This last structure is the most sophisticated; it allows the
greatest degree of independence among objects and therefore
the m a x i m u m amount of object reuse and encapsulation (both
of data and of functionality). Theoretically, you can construct
a system in which objects know nothing about one another
but simply post and respond to the appropriate notifications.
Be aware that this structure~which may allow significant
savings in development time--may exert a toll at run time. In
practice, the objects must know something about one another;
if they don't, you are likely to wind up with a glut of notifica-
tions (most of which are not acted on). Even worse, objects
that expect to receive notifications may not act on them be-
cause the notifications are not what they expected to receive.
A further difficulty with implementing notification-based ar-
chitectures lies in the fact that many programmers remain un-
comfortable with the idea. They simply don't trust the system
to do the right thing; they are much more comfortable with
using the 50-year-old paradigm of procedure calls. However,
to move into a robust, sophisticated, multiuser model (even
the limited version of it that consists of multiple applications
running simultaneously on a single computer), it is necessary
to trust the framework that you use.
Furthermore, overuse of notifications can make debugging
excruciatingly difficult, because you do not know why pieces
of code are suddenly executing (or not). But this fact is not an
argument against using notifications~it is an argument for
keeping them clear and simple so that they can be debugged.
The notification design, when properly used, can extend the
economies of object-oriented programming as individual pro-
grammers become more and more expert in their own objects'
functionalities and need to know less and less about other ob-
jects. Emotionally it may feel better to control all of your ap-
plication's objects and their methods; unfortunately, that is a
dead end, leading to closed systems, unmaintainable code,
and compromises with object-oriented design that will pro-
duce code that is just as spaghetti-like as the worst legacy Co-
bol code (it just will take longer to reach that point because the
object-oriented technologies will sustain you longer than Co-
bol did).
NSNotification An NSNotification object is at the heart of the
notification system. Although you can subclass NSNotifica-
tion, doing so is likely to defeat the elegant simplicity of the
design. A notification object has three fields:
0 The notification's name is an NSString that you select.
Senders and receivers of notifications should agree on
this string; it is usually much easier for development
teams to agree on a string name for a notification than
for a data structure or other shared information.
0 A notification contains a reference to an object. This is
usually the object that posts the notification (that is,
the object that causes the action that the notification
reflects). This object may be nil; it also may be another
object, but that design starts to m u d d y the clear design
of the notification system.
0 The notification may also contain a dictionary that
contains any additional information that the notifica-
tion might need. For example, if several fields of a
view are involved in a notification, the dictionary may
contain keys such as "Field I view" and "Field 2 view"
that are linked to specific objects. The dictionary is op-
tional.
The flexibility of the notification lies in its simplicity. The dic-
tionary lets you pass specific information in a common format
along with the notification. If you are familiar with Apple
events, you will notice that this structure is quite reminiscent
of the Apple event structure in which the common syntax al-
lows an Apple event to contain very specific descriptors of
meaning to its senders and recipients but which are transpar-
e n t ~ b u t transmittable~to others.
You can subclass NSNotification, but doing so immediately
makes your events less general. If you need to pass additional
information, pass it in the dictionary included with the notifi-
cation. Don't subclass NSNotification.
Once you have decided that you have something to notify
other objects about, you post the notification to the default no-
tification center for your task. The notification center contains
utilities for creating NSNotification objects.
serves as the clearinghouse for all notifications within that
task. Notifications can be created by any object in the task and
posted to the notification center. Independently, any object
can register itself as an observer of notifications. As noted in
the previous section, a notification has a name and optionally
has an object (usually the originator of the notification) and
user information in a dictionary.
Observers can register to receive notifications based on name
or originating object~or both, or neither. If the registration
omits both the name and object, all notifications within the
task are forwarded to it; if either or both are provided, only
those notifications from the chosen object or with the given
name are forwarded. When registering, an observer passes in
a selector, which is a reference to one of its methods that will
be invoked by the notification center. If a notification needs to
be forwarded to an observer, that observer's method will be
called and the NSNotification object passed as the single argu-
ment to it. You m a y name this method anything you want
(but something like ProcessNotification w o u l d n ' t be such a
bad idea). The NSNotification center makes very few de-
mands on either notifiers or observers; the architecture is sim-
ple and robust.
A notification center uses an NSNotificationQueue to manage
the notifications. The notification queue normally functions as
a first in-first out queue, but the default NSNotificationQueue
also provides the ability to merge similar notifications ("coa-
lescing") and to remove events matching some criteria (name,
object, etc.). Changing the w a y in which notifications are en-
queued or dequeued can lead to problems later, so unless you
are absolutely certain that you know what you are doing, stay
out of the NSNotificationQueue. You are likely to optimize
the performance of your application in a single-user, single-
processor, non-networked environment.., and lay the
grounds for a disaster later on. Assume that the notification
center uses a first in-first out queue and furthermore assume
that it may function asynchronously (even though it does not
in the simplest case).
Here are some code snippets from the Diary example that
show h o w you can use delegates and notifications.
ta, and then it moves the object's data into the interface fields.
When the data is changed anywhere in the application, a no-
tification is posted, and the interface is refreshed with the new
data.
Java:
Objective-C"
Note that you implement these methods, but you m a y never
call them. The point of notifications is that the dispatching is
done by Cocoa. In fact, in Diary, you sometimes call these
methods directly without a notification--in windowCon-
t r o l l e r D i d L o a d N i b they are called to move data from the
current entry object that exists after opening a w i n d o w into
the interface:
Java:
Objective-C"
Notification receivers have a single argument, an NSNotifica-
tion, which can be null as in this case. If it is not, you can use
data from the NSNotification object which was put there dur-
ing the registration process described next.
Registering for notifications is done before you could possibly
The a d d O b s e r v e r method registers your code for a notifica-
tion. In most cases, you register with your task's default noti-
fication center, which you can obtain dynamically from the
NSNotificationCenter object.
There are four arguments to the a d d O b s e r v e r method:
1. The first is the object to be notified.
2. The second is the method in that object to be called.
3. The third is a string that, if it is part of a posted notifi-
9
cation, triggers this action. (Such strings are part of
many header files~windows, views, NSApplication,
and so forth; they can also be your own.)
The fourth is an object that, if it is part of a posted no-
tification, triggers this action.
Java"
Java uses NSSelector objects to register for a notification. You
typically create them dynamically as in the underlined line of
code in the following snippet. You specify the method to be
called when the notification is received, and you pass in the
parameters for the class specification. This is boilerplate code
starting from the arrClass declaration; all you normally
change is the name of the method to be called and the name of
the notification. In the first notification, for example, when the
is called.
The notification strings are defined here:
Objective-C:
Objective-C uses a selector data type for the second parameter
as shown here:
9
The string declaration in another header is shown here:
Posting a notification does not require registration. You fre-
quently receive more notifications than you send, as you can
use the declared notifications of documents, views, windows,
the application object itself, and other Cocoa objects. These are
sent at appropriate times; you need merely register to receive
the notifications.
For your internal processing, however, you frequently post
notifications to yourself to provide consistency among inter-
face elements. In Diary, for example, calling the a d d E n t r y
method in DiaryDocument causes a notification to be posted:
Java:
Objective-C:
This is the first notification registered in the code in the previ-
ous section; it causes l o a d F i e l d s F r o m D i a r y D a t a to be called.
Thus, the following processing occurs:
0 The DiaryData a d d E n t r y method is called" It creates
a new DiaryEntry object and makes it the current en-
try.
As a result of the posting of the notification, the Diary-
The w i n d o w S h o u l d C l o s e method is a delegate of NSWin-
dow. It is implemented in the TextEdit example document
Notifications class. It runs when the NSWindow's w i n d o w S h o u l d C l o s e
message is sent/method is called and is passed on to its dele-
gate--the document, in this case.
Java:
Objective-C:
Delegates are specified in the header of the class to which the
delegate will be attached (in other words, NSToolbar specifies
the delegate methods you implement in the document or win-
dow that will be the delegate). They are called as needed, and
their structure is variable. In many cases, including those
shown here, a delegate returns a boolean indicating whether
a proposed action can take place. Thus a delegate is prospec-
tive in nature.
The notification methods are called automatically through the
notification center. In general, notifications are retrospective:
They are called after something has happened. Furthermore,
their structure is not open as is that of delegate methods. No-
tifications pass an NSNotification object from which you need
to extract the relevant information for your processing.
With its events and responders, Cocoa is similar to a number
of other application development frameworks. However, it
adds the powerful delegate and notification systems to more
traditional event handling.
You can combine event handling and the basic building
blocks of the previous chapter to implement sophisticated ap-
plications in Mac OS X, but one more thing is needed: the vi-
sualization in windows. That is the topic of the next chapter.
The heart of a graphical user interface is its graphics~its views,
windows, images, and the other visual elements that appear on your
computer's display. This chapter examines how to handle those ele-
ments in Mac OS X.
The sections of this chapter focus on:
9 Views~the basic graphical elements of the interface
Windows~the containers of views, images, text, and other
graphical elements
Images~JPEG, TIFF, or other images that are displayed in
the interface (but are not part of its interactivity)
Toolbars---one of the most attractive features of the Aqua
interface
Drawers~an "ooh"feature of Aqua that demonstrates that
windows need not be rectangular
Note that controls~buttons, sliders, pop-up menus, and the like~
are dealt with in Chapter 21.
In the C++ frameworks of MacApp and PowerPlant, views
are a generalized class that descends from an event handler
class. Windows are a specialized type of view.
In Cocoa, views and windows are descendants of a similar
type of object~NSResponder. However, windows and views
are equal descendants of NSResponder: Windows are not de-
scendants of views.
It should scarcely be surprising that an enormous amount of
work has gone into handling the windows in graphical user
interfaces. After all, they are the interface for most users. A
number of different strategies have been used to display them
and to manage their interactions. In Cocoa, you will find a
class of window controllers that manage windows. If your ap-
plication has multiple windows, it will normally have multi-
ple window controllers.
View Hierarchies of views function as they do in any f r a m e w o r k ~
they let you create groups of views that may contain others.
Note that the run-time view hierarchy is not the inheritance
hierarchy of object-oriented programming. A superview is
not a superclass.
The hierarchy of views is logical and not related to their phys-
ical locations. In other words, a view that contains another
view simply contains it; its location is irrelevant to the con-
tainment. In fact, the list of contained views m a y be ordered
in a w a y that is totally different from their visual representa-
tions.
Each view may have one or more subviews that are contained
within it (both physically on the imaging device and logically
within the object). A view m a y also have a superview in
which it is contained. The topmost view in a w i n d o w hierar-
chy is the content view. The content view has no superview;
it is contained within its window, and the w i n d o w has a spe-
cific reference to its content view. From the content view's
subviews (and their subviews) you can reach all of the views
within a window.
You normally size and shape views in Interface Builder. Al-
though they are often resized during p r o g r a m execution, this
resizing is commonly in response to user actions, and you
don't get involved.
As in most frameworks, each view has its own coordinate sys-
tem. In the framework, the (0,0) point is typically the lower-
left corner of the view. You can flip the view's coordinate sys-
tem so that the vertical axis increases from top to bottom and
the (0,0) point is at the top left. Each view has conversion rou-
tines that let it convert points and rectangles from other
views' coordinate systems to its own.
One difference from some other frameworks is that views can
be rotated. They need not always appear with their "vertical"
dimension pointing up.
Two rectangles are important for views:
1. A view's frame identifies its location in the coordinates
of its superview. The frame determines the view's size
and shape. It contains the Aqua interface shadow
d r a w n around controls and windows.
0 A view's layoutRect is the view's frame without the
shadow.
You can use Interface Builder's Info window to set view
bounds and frames as shown in Figure 20-1.
The size pane provides a pop-up menu that lets you switch
between the frame and layoutRect values. Below that, two
pop-up menus and associated text entry fields let you specify
coordinates and size for the view.
You can use any pair of coordinates that you want. Mac OS 9
and earlier (including Carbon) relies on a coordinate system
with 0,0 at the upper left of the display (this is where the CRT
electron scanning gun starts on old video monitors). Cocoa
uses an origin of 0,0 at the lower left. This makes the upper
right of four quadrants the primary location for screen dis-
play. This is consistent with the general use of two-dimen-
sional coordinate systems in which the positive quadrant
(upper right) gets most of the attention.
Whatever view you have selected in your interface is reflected
in the Info window. You can resize and move views in their
enclosing w i n d o w and the coordinates in the Info w i n d o w
will change.
Note that in the right-side (size) pop-up menu, a Default item
is available. Interface Builder will size the selected object as
well as it can.
The behavior of views when their superview is resized is not
a simple issue. Both size and location come into play. For ex-
ample:
When a w i n d o w is resized, buttons within it are nor-
mally not resized: Buttons are often of a standard size.
When a w i n d o w is resized, buttons that are located in
specific locations are often moved relative to the edge
of the view (that is, the OK button is usually a fixed
distance in from the lower-right corner of the view).
The frame of a view within a resized w i n d o w is often
resized directly with the window: Making the win-
dow one inch wider normally increases the size of its
content by one inch.
The information within a frame (text or g r a p h i c s ~ t h e
contents of an e m b e d d e d view's bounds rectangle) is
normally unaffected, although the change in the em-
bedded view's frame m a y make more or less of the
content visible.
If you want to handle this programmatically, the framework
provides two sets of three constants that you can OR together
to control the resizing behavior of a view w h e n its superview
is resized. For width, the three constants are as follows:
0 allows the left (min) horizontal
margin to vary.
0 NSViewMaxXMargin allows the right (max) horizon-
tal margin to vary.
Q NSViewWidthSi z a b l e allows the view itself to be re-
sized.
Three similar constants are provided for YMargin and the
height.
With Interface Builder, you can use the Info w i n d o w ' s Size
pane to manipulate these values. Figure 20-2 shows the basic
controls.
The schematic diagram at the bottom of the Size pane repre-
sents a view (the inner square) within its superview (often a
window). You can click on the horizontal or vertical springs
and struts to switch between keeping the selected view a con-
stant size (struts) in that dimension as the superview is re-
sized or resizing it proportionately (springs).
In Figure 20-2, the horizontal dimension is set to resize pro-
portionately as the superview changes; the vertical dimension
is set to a constant value.
You can use the parts of the axes outside the inner view to in-
dicate its behavior with regard to location. In Figure 20-3, the
inner view is set to be a constant distance from the left margin
of its superview, while its top moves proportionately to the
resizing of its superview.
Use the Interface Builder Test Interface c o m m a n d in its File
menu to see how setting these options changes your view be-
havior.
There really are only two methods that you need to worry
about w h e n it comes to drawing views: and
(that is, draw something like a graph or diagram based on
changing data rather than drawing an object such as a button
or text field), you will probably need to use the NSBezierPath
class.
drawRect Actual drawing within a view is done by
drawRect. If you use standard views (buttons, text fields,
and the like), Cocoa does all the drawing for you. If you im-
plement a custom view class, you must implement
d r a w R e c t , otherwise, nothing will be drawn.
Before your d r a w R e c t method is called, all the coordinate
conversion and focusing are done for you. You can draw
starting at your view's 0,0 coordinate (its lower left), and you
can know that everything will appear properly in the window
no matter where the view and the window are located on the
display.
A single parameter--an NSRect--is passed in to d r a w R e c t .
You can use it to optimize your code. It represents the smallest
rectangle within your view that needs redrawing. If your
view is very complex, this can be a major efficiency. If draw-
ing the view is not particularly burdensome, the extra pro-
gramming and processing to analyze the part that needs
redrawing may not be worth the effort.
Remember that you need to implement d r a w R e c t only for
your custom views. Even if you override a standard Cocoa
view object, its d r a w R e c t method may still be satisfactory for
your purposes.
0 You can specify that the entire view needs (or does not
need) redrawing by passing in a boolean.
9
0 You can specify the rectangle within the view that
needs redrawing.
Using the rectangle makes for greater efficiency, b u t ~ a s with
the case of d r a w i n g ~ c a n make code more complicated.
Below are the headers for both versions of s e t N e e d s D i s -
p 1 a y along with a snippet of code from Sketch. This is a very
common type of drawing code. The custom view (of which
this is a method) contains a variety of graphic objects. The cus-
tom view has a method called i n v a l i d a t e G r a p h i c (shown
here) that invalidates a specific object that is passed in as a pa-
rameter. All it does is to call s e t N e e d s D i s p l a y passing in
the object's bounds. (Diary does not use this sort of code be-
cause its drawing is confined to controls, not user-created ob-
jects that can be of irregular shapes and sizes.)
If your view contains objects whose size and location you do
not know, you could use the other version of s e t N e e d s D i s -
p 1 ay, and just pass in a value of TRUE so that the entire view
is redrawn.
Java"
Objective-C"
,o,
N S B e z i e r P a t h This is the core of the drawing mechanism in
Cocoa. It is based on the cubic equation developed by Pierre
B6zier for CAD/CAM systems in the 1970s, which later be-
came the basis for Adobe's PostScript model.
A path is an ordered sequence of data points. The lines and
curves that join them may form a recognizable shape (line,
rectangle, or circle), and convenience methods help you create
such shapes. A path may be closed; if it is, its enclosed area
can be shaded and otherwise manipulated.
NSBezierPath contains most of the drawing tools that you
need. You can specify arrows for the ends of line segments,
line dashing, and width for lines.
In addition to the drawing tools, NSBezierPath manages hit
detection: It can report if a given point is contained in itself.
If you are used to programming in PostScript, you will be
right at home in the NSBezierPath class. If you are used to the
QuickDraw routines in Mac OS 9 and earlier, you also will
find NSBezierPath familiar. (On Mac OS X, Quartz imple-
ments much of the functionality that QuickDraw did on Mac
OS 9 and earlier; however, you get to many of the basic draw-
ing routines through NSBezierPath.)
If you need to draw images on the fly, look at the documenta-
tion of NSBezierPath (search for it by name using Cocoa Help
from Project Builder). However, before doing this, consider
whether you really need to draw in this way. All of your in-
terface elements are drawn automatically by Cocoa; in addi-
tion, text in NSTextField or NSTextView objects is drawn
automatically. A great m a n y Cocoa programs require abso-
lutely no custom drawing.
Views are responders, and the handle events including mouse
tracking and mouse clicks. The default behavior of Cocoa
views is usually satisfactory; in fact, modifying it typically
breaks the user interface. Despite the fact that these subjects
are critically important and require a great deal of code to be
properly implemented, Cocoa takes care of them and imple-
ments them, so you rarely need to worry about them.
The only attention you need to give to these items is to use the
Info w i n d o w in Interface Builder to enable (or not) the views
in your interface.
Views in Interface Builder are easily manipulated by pointing
and clicking. If you need to manipulate views programmati-
cally, you need to be able to identify them.
If one of your objects needs to access a v i e w ~ e i t h e r to set or
retrieve data from it, to enable/disable it, or to remove it or
move it a r o u n d ~ i t needs to be able to identify it easily. The
simplest w a y to handle this is to make the view in question an
outlet of your object.
Two sections of code from the examples show how you can
add views dynamically, a d d P a g e is used in TextEdit to add a
new page of text w h e n the user is using the Wrap to Page
Each of these methods is standard code, and each demon-
strates common issues that arise w h e n you add views.
There are three steps involved in dynamically add-
ing a view:
1. Get a reference to the view into which it is to be placed.
2. Create the n e w view.
3. A d d it.
The relevant lines of code are underlined in the following
code snippets. The only item that needs to be pointed out is
that it is c o m m o n in finding a reference to the v i e w to be add-
ed to that it m a y need to be fished through some intermediate
views. In this case, the object that is adding the page has a ref-
erence to a scroll view, and it needs to retrieve a d o c u m e n t
v i e w object from that one.
Java:
Objective-C:
At the bottom, the newly created button refuses to ever be the
first responder. It is still enabled, and it still responds to users'
mouse clicks, but it is out of the responder chain, and events
other than mouse clicks do not go to it.
Finally, it is added to the view as before.
Java:
Objective-C:
You can create a v i e w hierarchy
in Interface Builder by dragging v i e w s into the nib w i n d o w
(they do not have to be in their o w n w i n d o w s ) . If y o u create
an outlet in your object, you can connect such a w i n d o w l e s s
v i e w to that outlet. You then can use a d d S u b V i e w to add that
v i e w w h e n you need it.
See the next section for information on adding views to win-
dows.
You sometimes need to remove a view from its hierarchy. The
r e m o v e F r o m S u p e r v i ew method does that. Note that this is
the method of the view that you are removing: Cocoa takes
care of fixing up the superview's hierarchy, responder chain,
and the like.
Cocoa windows are much lighter-weight objects than you
may be used to working with. In the first place, they are not
descendants of the view class, so they do not bring with them
a whole host of methods that are frequently overridden to re-
move view functionality from windows.
In the second place, window controller objects (NSWindow-
Controller) manage loading, titling, and closing the window.
Window controllers normally work with nib-based windows
that you create in Interface Builder. There is usually one win-
dow controller per window.
Because windows are not views, and because window con-
trollers handle their creation, windows have four primary
roles to play:
Q They manage the display of the view hierarchy within
them.
2. They manage event dispatching to those views.
0 They manage a text field editor that is shared among
all of their text views.
4. They have a delegate that responds to events that af-
fect the w i n d o w (resizing and zooming).
Very much like views, windows are critical and pervasive ob-
jects in the f r a m e w o r k ~ b u t they are overridden even less of-
ten than view objects. Windows, after all, not only display
their views' data, but also are responsible for interacting with
the Window Server and managing events and menus. Chang-
ing their appearance or behavior is often a mistake.
Occasionally, it is appropriate to add functionality to win-
dows (rather than changing default behavior). You can do this
easily by adding a delegate to the w i n d o w - - a n d this is com-
mon, easy to implement, and quite appropriate.
Rather than override an NSWindow, you typically add a del-
egate to the window. For example, a w i n d o w delegate can im-
plement w• ndowwi 11 r 1 o s e in order to do special processing
as a w i n d o w is about to close.
The w i n d o w delegate methods are listed at the bottom of
NSWindow.h.
Window notifications let you know when something will or
has happened to a window. They are listed at the bottom of
NSWindow.h along with the delegate methods. An object can
t i f i r a t i o n to do special processing at that time.
Figure 20-4 shows the Interface Builder Size pane in the Info
w i n d o w for a window. You will note that in addition to the
values you can set for views, there are other fields that you
can use to set the m i n i m u m and m a x i m u m sizes of a window.
You also can specify how it can be moved on the desktop.
Each w i n d o w loaded from a nib file normally has a w i n d o w
controller. A variety of w i n d o w controller m e t h o d s are called
as the w i n d o w is created, and you can override them to set its
title and otherwise manipulate the w i n d o w just before it is
shown.
Customizing the w i n d o w title is frequently needed w h e n a
w i n d o w displays the contents of a document. As a result,
hooks in N S D o c u m e n t let you access the controller during the
load process, and you can generally avoid overriding NSWin-
dowController.
One reason to override a w i n d o w controller is w h e n you have
subsidiary nib files containing their o w n objects. The w i n d o w
controller can take responsibility for freeing the objects in the
nib file w h e n the w i n d o w is closed and they are no longer
needed. You can install your w i n d o w controller as a delegate
(implementing wi ndowW i 11 C 1 o s e) or register for a notifica-
tion ( W i n d o w W i l l C l o s e N o t i f i c a t i o n ) to do this.
If you do override NSWindowController, you normally over-
ride the following methods. You rarely call w i n d o w controller
methods (either original or overridden); Cocoa's default win-
d o w loading and manipulation code works just fine.
Java:
Objective-C:
The most basic (and frequent) use of w i n d o w s is to have them
open automatically from your main nib file along with the
views and controls that you have placed there using Interface
Builder. The second most basic and frequent use relies on a
document; whenever a new document is created or an old one
is opened, a w i n d o w is opened to display the contents of the
document. Both of these scenarios are implemented as tem-
plates in Interface Builder.
There are some more advanced and sophisticated issues that
need to be addressed:
9 Interrupting the loading of nib files to modify data in
the w i n d o w
9 Setting position and responder status
9 Programmatically adding views to a w i n d o w
Two methods of NS-
the views and controls in the w i n d o w are
not yet there; however, you may do this is you need to pre-
pare something that does not require them.)
Here is a method from Diary that overrides winflowCon-
trollerDidLoaflNib in order to fill the w i n d o w ' s fields
with data. Sketch does a similar process.
Several points about overriding
L o a dN i b are worth noting:
Although it is a method of NSDocument, it provides
you with access to the w i n d o w controller (its argu-
ment) as well as to the w i n d o w itself (via the control-
ler's w i n d o w accessor). If you need to store references
to either one in your document, you can do so here.
Toolbars, which are totally dynamic objects, need to
be added to windows after they are created and just
before they are displayed. This is the right hook to do
that.
Java:
Objective-C:
ooo
is handled in most cases in response to a mouse click.
However, sometimes when you open a window, you want to
set them up manually. Again, w i n d o w C o n t r o l l e r D i d -
LoadNib (for NSDocument objects) or one of the window del-
egate or notifications is the right place to do this. The relevant
methods you might call are:
Java"
Objective-C"
sender (an Object in Java, an id in Objective-C). In most usage,
the sender is irrelevant and is set to null.
specific view (usually a control) to the head of the window's
responder chain. (If the window is the key window, the win-
dow itself is at the front of the responder chain.) To use this
method, you must have an identifier for the view to be made
the first responder. It must be linked to an outlet, or it must
have a tag that you can use to find it.
If you have saved w i n d o w positions, you can restore them
here. See "Saving Window Positions" on page 389.
Setting Subviews Sometimes all or part of the w i n d o w ' s con-
tent view is created separately~either dynamically or as a
separate hierarchy in Interface Builder. If you need to set a
w i n d o w ' s view, use s e t c o n t e n t v i e w .
The biggest difference between imaging in this framework
and imaging in other frameworks is the coordinate system
that is used. In both cases, the horizontal axis running from
left to right starts at zero and goes up. In the case of Mac OS 9
and earlier, however, the value of zero on the vertical access
is at the top of the screen; in Cocoa, it is at the bottom. As a re-
sult, Mac OS objects were often located on the screen (or in a
view) by means of their top-left point; in Cocoa, it is often the
lower-left point.
Drawing normally takes place within views. Images are light-
weight objects that you can draw without using a view. The
image thus d r a w n can then be quickly moved to a view for
display or printing.
Images can be in various formats; a single image may contain
multiple representations of the same image using different
formats. Each representation is an instance of a descendant of
NSImageRep.
If you are coming from another framework, you can realize
the efficiencies that images offer you: You have very little
overhead and you don't have to worry about the representa-
tion.
NSImage is responsible for managing all of its representations
and for selecting (and drawing) the appropriate one for a giv-
en device. For convenience, images may be named.
Each NSImage may have a delegate that implements i m a g e -
DidNotDraw (aRect--NSRect). This method is called only if
NSImage was unable to draw the image. It returns an NSIm-
age*--which could be an alternative image to draw. If it re-
turns nil, NSImage no longer tries to draw the image,
assuming either that the delegate has done so or that no image
should be drawn.
The image representation is what actually does the work for
the image object. NSImageReps are created from raw images
in files, on the pasteboard, and data objects in memory. The
NSImage class maintains a registry of the image types that it
can handle and the subclasses of NSImageRep that should be
created for each one. Filtering services that may be present on
a given system can expand the range of image types that are
handled; NSImageRep provides methods for including or ex-
cluding filtering service conversions.
If you are not adding a new type of image representation, you
can probably ignore this section: NSImage manages the pro-
cess for you. The most probable case where you may need to
be involved is one in which your application relies on specific
filtering services.
Toolbars, one of the most useful and distinctive aspects of the
Aqua interface, are totally dynamic objects. You may think of
them as views and controls, but in reality, they usually are
not. They are built at run time, and doing so brings together a
n u m b e r of the concepts discussed in this chapter and the pre-
vious ones.
Here are the steps in using a toolbar:
1. Declare names for the toolbar items.
2. Set default toolbar items.
0 Set allowable toolbar items (for all toolbars, but neces-
sary for customizable toolbars).
4. Create the toolbar w h e n the w i n d o w is about to open.
1 Return NSToolbarItem objects on demand; they dis-
patch the appropriate methods in response to user
clicks on the images in the toolbar.
The Diary toolbar contains five icons:
1. N e w
2. Delete
3. Next
4. Back
5. Drawer
Note that each of these items corresponds to a method in the
application. Furthermore, each of those methods can also be
invoked from the m e n u bar. Because a toolbar is visible or not
at the user's option, you must provide an alternative w a y of
getting to its functionality.
Each toolbar item has a string identifying it; these are not the
strings that appear if the users select the option to use names
and icons. (See "Create Toolbar Items for Response to User
Clicks" on page 447 for those strings.)
Java:
Objective-C:
You must set a delegate for your toolbar (in Diary and many
other applications it is the main document object, because that
is guaranteed to be o v e r r i d d e n ~ N S W i n d o w is usually not
overridden, nor is NSApplication.) The delegate must imple-
ment all of the NSToolbar delegate methods. If it does not, the
se t D e l ega t e method will fail and display an error message
on the console in Project Builder (in debug mode).
This is boilerplate code. First, you create a mutable array that
will be returned as the result of the function. Then, you add
the string constants you declared to the array. Finally, you re-
turn the array which, at this point, consists merely of an array
of String objects (Java) or NSString* objects (Objective-C).
Java:
Objective-C:
You need a similar array of strings representing the allowed
toolbar items. The only difference in Diary is the name of the
method. (In customizable toolbars, the default array is usually
smaller than the allowed array.)
Java:
Objective-C:
When the w i n d o w is created and about to open, you need to
create the toolbar. Here is the code to do that; all you do is
change the names of the toolbar elements.
Java:
();
( theToo lbar) ;
Objective-C:
For each of your potential toolbar icons, do the following:
1. Create an NSToolbarItem object.
0 Check whether the item clicked (i t e m I d e n t i f i e r )
matches a specific toolbar item name that you set us-
ing the constants in step 1.
0 Set a label to appear under the icon (if the toolbar dis-
play mode is set to do so--here the default is used, and
it does display a label).
4. Provide a tool tip.
0 Set the item's action--you create a selector for the
method to be linked to the icon.
6. Set the image for the icon.
Java:
Objective-C:
Unlike toolbars, drawers are actual view and w i n d o w objects.
In fact, they are a trio of objects: a window, a drawer object
that provides the functionality, and a content view that is
placed within the drawer.
You can create them dynamically in Interface Builder. A pal-
ette item provides all three w h e n you drag it into a nib. The
only additional piece of functionality that you need is the abil-
ity to open and close the drawer in response to user actions.
1. Declare an outlet in your object for the drawer:
Q Link the drawer to an outlet in your object using Inter-
face Builder.
0 As needed, call the NSDrawer object's t o g g l e D r a w -
e r method:
Java"
Objective-C:
This chapter has provided you with an overview of the main
Aqua interface elements, views, and windows, along with
two of the more interesting additions to the developer's set of
tools~toolbars and drawers. Compared to other frameworks,
there is less overriding in Cocoa: You focus in on what you
want to do, and accomplish it using techniques such as dele-
gation.
In fact, there is even more to visualization~special views to
manage scrolling and text, for example. They are similar to
objects in other frameworks, and you generally use them in
Interface Builder without modifying them.
The next chapter--which deals with controls~also touches
on features that are common to other frameworks. It, though,
is more specialized than this chapter. Interface Builder and
the ability to wire objects together easily using a graphical
user interface (for the programmer!) make the deployment
and programming of controls much easier in the Cocoa envi-
ronment.
Except for command line tools and services, almost every Mac OS X
application has a graphical user interface. The design of that inter-
face is up to the application developer, but Apple provides an abun-
dance of guidance, assistance, and resources to help you develop the
interface. The reason for this assistance is twofold:
Apple wants to help developers produce software that, in
turn, drives sales of its products.
The overall look and feel of a computer running Mac OS X
is more consistent and satisfying to users when all applica-
tions adhere to standards.
If you are using Cocoa, MacApp, or PowerPlant, you have taken a
large step toward consistency and standards. The buttons, text
fields, sliders, and other controls that you implement are drawn by
the respective frameworks and they implement Apple's interface
guidelines.
This chapter addresses the general issue of guidelines and standards
and explains why they are important for your application. It then
walks through each of the interface elements that you can use in In-
terface Builder, providing you with the terminology, human inter-
face guidelines, and relevant programming topics for each one.
These interface elements are grouped into three categories:
Action controls such as buttons that users employ to initiate
(or stop) processing.
Interface elements that allow users to enter data~text,
choices, and the like.
Output elements that provide information to users from the
program.
The focus of this chapter is on the Aqua interface, which can be im-
plemented both in Cocoa and in Carbon. You can use Interface
Builder in both environments, although if you have a Carbon appli-
cation that does not use nib files, it is not particularly productive to
do so.
From its start in 1984, the Macintosh computer has led the
way for the industry in hardware and software design. Be-
cause design has been a key component of the Macintosh, Ap-
ple has promulgated its design guidelines and standards to
developers so that all Macintosh applications can look and be-
have as similarly as possible. Consistency of interface design
means that the learning curve for a new application is much
less challenging for users.
The behavior of interface elements is even more critical than
their appearance. The disclosure triangle that lets you expand
lists and dialogs is now widely recognized by users, as is the
sort order triangle that appears at the top of columns in list
views. Both are shown in Figure 21-1.
When you think about it, these interface elements (widgets, to
some) are extraordinarily complex. Their behaviors are sim-
ple: disclosing or hiding details and sorting a list. However,
what they do depends on their context. A triangle pointing
d o w n or to the right and located in the margin of a list is a dis-
closure triangle; one pointing up or d o w n and located in the
title of a column in a list view is a sort button.
Yet, having used such interface elements once, most users un-
derstand what they are and have no problem using them in
other environments. Even a somewhat different use of a dis-
closure triangle (in the Save sheet shown in Figure 21-2) is
usually not a mystery to users who see it for the first time.
Remember that most people are totally uninterested in learn-
ing h o w to use your program's interface: They are interested
in doing what your program lets them do. Whenever some-
one focuses on a tool rather than the task, something is wrong.
It is very important to Apple's ease-of-use reputation that all
of the applications running on the Macintosh adhere to the
guidelines. Your creativity should be focused on the sub-
stance of your application, and not on inventing new interface
widgets.
If you need a new interface functionality, try to use existing
interface elements in a new and consistent manner. For exam-
ple, it would probably be a poor choice to decide that a trian-
gle could function as a zoom button. That is somewhat similar
to its normal behavior of showing and hiding information,
but the fact that zooming involves resizing the image is suffi-
cient to argue that it is not the same and a different element
should be used.
Interface functionality that applies (or could apply) to a vari-
ety of applications should use the standard elements if at all
possible. If you need changes or extensions that others might
want to use, check the Apple Developer Connection mailing
lists and forums to see what may be in the works.
When it comes to domain-specific functionality for your o w n
application, feel free to invent consistent and logical interface
elements that reflect the world of gene splicing, money sup-
ply management, and the like. Apple is not going to have wid-
gets for you, so there is no point looking.
In short:
1. Use the standard interface elements.
2. Do not redefine them.
Q Implement new interface elements that are specific to
your application and its world.
Apple's User Experience Web page (http://developer.ap-
p l e . c o m / u e / ) contains a host of documentation as well as ref-
erences to sample code. In particular, the Aqua Human
Interface Guidelines (downloadable in a PDF file) are essential
to any developer. During the development of Mac OS X, this
publication has been revised several times, so make certain
that you have the current version. (Sizes of interface elements
changed fairly late in the development process.)
Actions are initiated for the most part by buttons and toolbar
icons. A mouse click~sometimes modified with a keyboard
modifier~causes an immediate action to occur. Sometimes
the immediate action is the cessation of a p r o c e s s ~ a s in the
case of a Stop button for a copy command.
There are six types of controls that can cause immediate ac-
tions; four of them are buttons.
1. Rounded bevel button
2. Square button
3. Round button
4. Push button
5. Checkbox
6. Radio button
There are two basic pieces of information the designer has to
convey to a user w h e n it comes to user action controls:
1. You can click on this item.
0 An a c t i o n ~ w h i c h must be made clear--will occur im-
mediately.
This may seem self-evident, but look objectively at s o f t w a r e ~
even some of the best s o f t w a r e ~ a n d you will see interface
mysteries galore. Often in the specious name of "design" peo-
ple eliminate the subliminal clues that guide users. Clickable
items are normally b o r d e r e d ~ t h a t ' s a clue. H o w m a n y times
have you found yourself looking at an interface or Web site
and wondering what is hot? H o w m a n y times have you spent
an inordinate amount of time searching for something only to
discover that clicking on an apparently dead image (a corpo-
rate logo?) will do the trick?
Remember that context is important in the interface. Users of
the Aqua interface have come to know and love the toolbar.
There are usually no standard buttons in the toolbar; there are
normally no borders (unless they are part of an icon). Users
have had no trouble learning that any image in the toolbar is
clickable. This means that you must learn the converse: No
unclickable (i.e., decorative) elements can go in a toolbar.
As you will see in the Info w i n d o w in Interface Builder, you
can set a variety of attributes for each button, including the
following:
9 A title (such as OK or Cancel).
9 An icon.
9 A keyboard equivalent.
9 A sound to play w h e n the button is clicked. The
Sounds tab in your nib file contains a variety of sounds
(you can add others by dragging them in). Type the
name of a sound into the Sound field in the Info win-
dow and it will play in response to the mouse click.
9 Feedback b e h a v i o r ~ a m o m e n t a r y change or light of
the button; toggle, change from on to off; and so forth.
9 You can choose between normal and small sizes for
most of these buttons. Small sizes are useful for pal-
ettes and less important interface elements.
To explore these and other attributes, drag a button from the
palette into a view, change the settings, and use the Test Inter-
face (COMMAND-R)c o m m a n d to see what happens.
Not all of these buttons accept all of the attributes.
This is the most basic button. Users rec-
ognize it from its extensive use in the in-
terface to Mac OS X. You cannot place an
icon in this button, and you should use
the System font for the text. A small size is available.
A round button can contain an icon; if it does, its ti-
tle is normally included in the graphic. A small
size is available.
Rounded bevel buttons can contain icons.
They may or may not have text in them. You
can use bevel buttons with icons in them as
data input devices; the immediate action con-
sists of setting a programmatic value (such as
paper orientation in Page Setup). There is no
small size, but you can resize the button as you see fit.
Except for the border, this is the
same as a rounded bevel button in
its appearance and behavior.
These can be used as action controls, but normally they are
considered to be user input controls, setting values that will
be acted upon later when the user clicks OK (or some other
control). They are discussed later in this chapter in "User In-
put" starting on page 461.
This control, originally part of the Classic Mac envi-
ronment, is used for small adjustments to numerical
information (such as the hour or minutes in setting the
time). It also is used in contexts like that for changing
text (AM/PM,in the time). Using Interface Builder, you can set
its low and high values, decide whether it wraps around, and
set the increment. If you attach a stepper to an outlet, you can
access it programmatically from within Cocoa and set these
values dynamically. Usually, a stepper control is placed next
to a text field in which the results of its stepping can be seen.
There are four basic types of user input:
1. Text
2. Images
3. Multiple choices
4. Continuous choices
A text entry field is an NSTextField that
you can drag from the palette. Note that
there are several variations on NSText-
Field--this one is for brief data entry.
You select the font and other text attributes by selecting the
field in your window and using the Format menu in Interface
Builder.
Remember the imagination and creativity of users: There are
critical clues to indicate that this interface element is designed
to be typed in. Cocoa automatically handles tabbing among
data entry fields in a view. The tabbing proceeds from the up-
per left to the bottom right, stopping at each entry field along
the way. When ready for keystrokes, a focus ring appears
around a text entry field indicating to the user that is the des-
tination of keystrokes.
Spacing within and among text fields is critically important so
that they look good and so that users can read them. The
guidelines in Interface Builder help you adjust the spacing ap-
propriately. (Note that guidelines appear for text baselines,
which helps you make different-sized or different-font labels
match up with data entry text.)
It is useful to have a composite ob-
ject containing labeled fields that
you can use as a starting point for
developing a data entry interface.
Interface Builder provides such an
object. It is a group of two text en-
try fields and two static text label
fields.
You can expand this object as necessary. If you need to do so,
first select it in Interface Builder. Then, ungroup the objects
using the Layout menu. A d d more text fields (or select and
copy these) until you have the right number. Adjust the labels
and regroup.
The text view ob-
ject comes com-
plete with its o w n
text editing envi-
ronment and a
scroller that con-
tains it. You use
fields such as those
shown in the pre-
vious section for
small amounts of
data entry (one
line or less); a text
view is intended to
hold larger amounts of text, offer more editing functionality,
and provide the ability to add images. You can control all of
this from the Attributes pane in the Info w i n d o w for a text
view.
Text views (like text fields) support the clipboard, so users can
enter text by using the Paste command or from the keyboard.
Because this view in the Interface Builder palette comes com-
plete with its containing scroller, you have very little work to
do to implement sophisticated text manipulation of large
amounts of text.
Text input comes primarily from the key-
board. Image input comes through the
clipboard or through drag-and-drop.
(You can implement your own drawing
and image manipulation routines as is
the case in the Sketch example, but they
are not part of the Cocoa objects. In other
words, there is no NSDrawingImage view complete with
menu and palette commands.)
In addition to setting the size of an image view, you can set its
scaling characteristics. This is important not only when the
user resizes the window, but also when the image that the
user pastes into the image view is not the same size.
A color well object lets users store colors for
use in their applications. Clicking a color
well brings up the Color Picker. Selecting a
color from the Color Picker then places that
color in the color well.
Although the image input and color well objects as shown
here look quite similar, they are not identical. Notice the dif-
ference in the borders between the two. Also, in practice, they
are used at very different sizes. The color well is usually the
size shown here (after all, it merely contains a swatch of col-
or). The image input object is normally substantially bigger.
Also, the color well normally appears in a palette or with oth-
er tools, and the image input object appears in the context of
user data.
In addition to text and image input, users are often requested
to provide choices from discrete or continuous objects.
C h e c k b o x e s Checkboxes let users choose
yes or no from one or more elements. The
choices need not be mutually exclusive. A
small version of the checkbox is available. Checkboxes are
sometimes used to launch actions, but users typically do not
expect them to do so.
One very common use of a checkbox to launch an action is a
checkbox that, w h e n clicked, causes changes to the interface.
For example, if you click a checkbox labeled "Collate Pages,"
subsidiary checkboxes or radio buttons might let you choose
forward- or reverse-collating. (But remember that users like to
control the interface, and any such changes that may appear
mysterious can irritate users who then are frustrated in trying
to get back to data entry elements that they just saw a m o m e n t
a g o ~ a n d that subsequently vanished into thin air.)
Checkboxes often are grouped together (see "Groupings" on
page 468) into logically related items.
A set of checkboxes presents
independent choices to users; radio buttons
let users choose among mutually exclusive
choices. Because the set of choices is impor-
tant, radio buttons are normally grouped in
a box or otherwise set aside so that two sets of radio buttons
do not confuse users.
Radio buttons are available in small sizes. Like checkboxes,
they can initiate actions; however, the same caveats apply to
using radio buttons to launch actions as apply to checkboxes
in the same situation.
Radio buttons al-
low mutually exclusive choices, all
of which are visible to the user at
one time (subject to w i n d o w
scrolling). However, a set of more than about 4-7 at the most
is confusing to users. A pop-up m e n u provides a simple w a y
of handling a set of mutually exclusive choices that range
from that number up to about 12. The choices are all visible at
one time, but only w h e n the user has clicked on the pop-up
menu.
Placing more than about a dozen items in a pop-up menu pro-
duces a scrolling list that is unmanageable. The government
of Canada had this in mind w h e n setting up the country's 10
provinces and 3 territories: A pop-up menu is fine for select-
ing one of them in an address. The 50 states of the United
States are eminently unsuited for a pop-up menu, but that has
not stopped interface designers from using them. (See Combo
boxes, in the next section, for ideas about dealing with the
states.)
The problems with long pop-up menu lists include the fact
that it is hard to navigate with the mouse d o w n to the right
choice and the fact that the long list often zooms off the top or
bottom of the display.
A pop-up menu appears with the current choice centered on
the control. That is, the menu can extend both above and be-
low the control itself, depending on where the choice is. A
pull-down menu extends below the control when the mouse
is clicked on it. A pull-down menu is distinguished from a
pop-up menu by a single d o w n arrow at the right rather than
the pair of up and d o w n arrows shown here. You can select
between the two in Interface Builder.
C o m b o Boxes A combo box com-
bines a text entry field with a pop-up
menu. Users can use one of the pre-
defined choices or they can type in
their own. A particularly useful feature is the Completes at-
tribute (set in the Attributes pane of the Info window). If a
user starts to type in the text field, Cocoa will pick an entry
from the pop-up menu that matches the keys processed so far.
Sliders
let users select
from a range of
values. Both verti-
cal and horizontal
sliders are avail-
able; each comes
with versions
with markers and
without. In fact,
all of these are
NSSlider objects
with various at-
tributes shown
(each of the four is
separately shown on the Interface Builder palette).
Placards allow
user input using pop-up
menus, buttons, or other
controls. They appear in
w i n d o w s ~ o f t e n in scroll
bars as shown here.
They are usually set programmatically and can contain any
control (or even explanatory information). The example code
for TextEdit was described in the previous chapter (see the
section "makeScalePopUpButton" on page 429).
In addition to allowing users to start actions and to enter data,
interface elements display information to the user. Sometimes
these roles merge. For example, users frequently can change
the information that is presented to them.
The same text field object that is used
Informational T e x t for data entry can also be used for
displaying unmodifiable text. The
Message Text Interface Builder palette has two
such objects that you can use. After
you drag one of them into your window, you click the text
field to enter text, and you use the Format m e n u to format it.
You can enable such a text field. That way, if a user clicks on
it, something will happen. In almost all cases, that is a mis-
take. Users normally do not click on text that is not editable
(the absence of a border and focus ring and the inability to se-
lect text are clues that this is not editable text).
A progress
bar can show
a user that
something is
happening. Feedback is important for letting a user feel in
control. Progress bars can be indeterminate (such as this one),
or they can be d e t e r m i n a t e ~ y o u change the attribute in the
Info window. Wherever possible, determinate progress bars
are better, because the user can get a sense of how much time
is left. Sometimes, however, it is impossible to calculate the
duration of a task.
If you are p r o g r a m m i n g something that may take quite a
while, do everything you can to provide a range of feedback
so that the user does not give up and force the application to
quit. One example of good user feedback for determinate and
indeterminate processes is the Installer. At all times, a list of
the tasks is visible at the left of the window. When each task
is performed, a progress bar of some kind is usually dis-
played. Thus, even if the user does not know how much time
is left in a given step, the status of the entire process is under-
standable.
Five ways of organizing information are available in Interface
Builder. The simplest is the ability to group interface ele-
ments; the others allow formatted and controlled displays of
large amounts of organized data.
A box can contain
. . . . . .
any n u m b e r of controls. You
can drag them into i t - - o r you
I can select them and choose the
Group In submenu from the
Layout menu. (You can group
items into a custom view, a
scroller, or a box.)
The box can be named, but it also can simply consist of lines.
You can use boxes to organize controls in a complex window.
However, remember that some of your controls will group
themselves. If you have a set of three radio buttons in a win-
d o w ~ a n d only that one set of three radio b u t t o n s ~ y o u do
not need to box them. If you have a set of three radio buttons
and another set of four, boxes are likely to be a good idea.
If you find
yourself grouping too
m a n y objects with boxes,
consider rearranging your
w i n d o w so that not all of
them are visible at one
time.
A tab view lets you place several views into a window. (Sys-
tem Preferences uses tab views extensively.)
For all practical purposes, six tabs are about as m a n y as you
can expect to put into a window; more than that means that
the tab titles start to merge. However, if you consider that a
tab view effectively allows you to make a w i n d o w up to six
times larger, it can be a very effective space-saver.
In organizing tabs, make their names descriptive and simple.
Tab I and Tab 2 (or Step I and Step 2) are not good names. To
edit tab views in Interface Builder, click the tabs to type in
new names. You can also add new controls to the individual
views. (See "Tab Views" on page 267 for help on doing this.)
Browser A browser is a
Browser very sophisticated w a y of
displaying rows and col-
umns of data. It is used ex-
tensively throughout Mac
OS X (in the Finder col-
umns view, for example),
and users understand its
functionality. (Users learn very sophisticated interfaces if
there is a consistent logic to t h e m ~ a n d if they appear fre-
quently.)
The definitive source for the browser is Tech. Note 2009 (lo-
cated on Apple's developer Web site at h t t p ' / / d e v e l o p e r . a p -
ple.com/technotes/tn/tn2009.html). The definitive example
is SimpleBrowser, which implements the Finder columns
view.
Browsers always have a horizontal scroll bar. Each panel has
a vertical scroll bar. Any of these may be disabled if the win-
d o w is big enough or the volume of data is small enough.
You set up browsers with descriptions of the data: element
IDs for the rows and property IDs for the columns. You then
provide callback routines for the browser to use: It will re-
quest whatever data is required when it is needed. Everything
that is involved with navigation is handled automatically by
the browser itself. All you do is provide the data.
Table View A table view im-
plements a basic table or
spreadsheet, and it manages
column resizing, selection, and
editing for you.
O u t l i n e V i e w Outline views, a
subclass of table views, are
similar to the Finder's list view.
They consist of entries which
can be opened or closed with
disclosure triangles.
Like the browser, an outline
view relies on you to describe
and later to provide the data.
Most controls have variants that are smaller versions of them-
selves. The small variants are not just scaled: They may use
different font sizes for their text, for example. You can use In-
terface Builder's Show Info window to select the small vari-
ants. They are useful for toolbars and for other subsidiary
purposes in windows.
This chapter provided an overview of the Aqua interface con-
trols you can use in both Cocoa and Carbon. They fall into
three groups: user action controls that allow the user to do
something with a mouse click, user input controls that allow
input of data (usually via the keyboard or clipboard), and user
information controls that display data to the user.
Each control has been named and identified. Using interface
elements consistently (and consistently with the Apple hu-
man interface guidelines) makes your application easier to
learn and u s e ~ i t also makes it look like (and be) a true Mac
OS X application.
In most cases, your application will appear next to other ap-
plications: Macintosh users have always used a number of ap-
plications at the same time because of the similarity of their
interfaces. In a shared environment like this, not only is it im-
portant to make your application fit in visually, but you also
have to be a good neighbor, sharing the computer's resources
properly. That idea is explored in the following chapter.
This Page Intentionally Left Blank
"'Sharing" is used in its broadest sense in this chapter. It refers to the
sharing of computer resources and of data over time and space. You
may think of sharing as something that doesn't affect you or your ap-
plications~you are resolutely single-user and single-machine in
your design. But sharing affects almost every user and every appli-
cation.
You share the processor and all of the computer resources with the
operating system; when you copy data from one application to an-
other, you are sharing it via the clipboard; and when you open a doc-
ument that you created yesterday, you are sharing the data that was
stored then. Beyond that, if your computer has two or more proces-
sors, they share the responsibility for running your application (and
any other work that they may happen to be doing). Within your ap-
plication, you may choose to use several threads that can process
more or less simultaneously as the operating system optimizes the
sharing of its resources; and within your application~even if it is
single-threaded~your objects may share themselves and data ele-
ments.
Cocoa provides the tools to do all this at a very basic level~so basic
that you may not even be aware of what it's doing all the time. Your
awareness and implementation of sharing are limited to implement-
ing a few class-specific methods and calling some memory manage-
ment methods~if you need to do so.
All of the classes and methods in this chapter are widely used. Ar-
chiving and unarchiving objects are the essence of Interface Builder
(you create the interface objects, it builds them, then archives them
in a nib file). The coding methods and protocol are used both for ar-
chiving and for clipboard and services support. The locking protocol
and methods are used for synchronism throughout the system.
NSThread, of course, is the heart of multithreaded applications.
All object-oriented programming languages make it very easy
to create objects at run time--nothing could be simpler. How-
ever, as soon as it is necessary to store that object on disk or to
move it to a different address space or run-time environment,
problems crop up.
The archiving and distribution architecture is described in
this section. The sophisticated handling of moving graphs of
objects to and from memory is done for you by the frame-
work; even the work of managing small graphs of objects (the
views of a window, for instance) is done by standard objects
(such as NSView). You don't have to worry about how it hap-
pens. ("Graph" in this sense refers to the structured collec-
tions of objects that may relate to one another, such as the
controls within a view that in turn is located within a win-
dow.)
Archiving is the process of taking objects from memory and
storing them on disk (it actually includes both archiving and
serialization~the distinction will be made shortly). Distribu-
tion is the process of taking objects from your application's ad-
dress space and preparing them for transfer to another
address space dynamically. Both archiving and distribution
are based on the abstract superclass NSCoder and on the
NSCoding protocol. NSObject adopts the NSCoding protocol
and has specific methods to support NSCoder and the
NSCoding protocol. As a result, all NSObjects have the basic
ability to be archived and distributed (although not all imple-
ment the protocol).
Archiving is the general process of moving objects from mem-
ory to disk, and vice versa. Where a distinction needs to be
made in the direction, unarchiving is used. It is noted in the
text that archiving refers only to the to-disk direction. Other-
wise, archiving is used without regard to direction.
Coding is the process of converting an object to a format that
can be shared~either on disk in a file or with another process
on the same machine or elsewhere on the network. NSCoder
objects are passed around in various NSObject methods as ob-
jects are being encoded and decoded. In practice, the objects
that are passed around are descendants of NSCoder: NSAr-
chiver and NSUnarchiver for files, and NSPortCoder for pass-
ing objects to another process or another machine on the
network.
Archivers use NSData objects to store their data; those objects
are then read to or written from disk. Archiving works with
full-fledged objects. The result of an unarchive method is an
NSData type that can be immediately coerced to the type that
you know it is.
Archivin@ As the following code snippets from Diary show,
you can archive an object by passing it to the a r c h i v e d -
D a t a W i t h R o o t 0 b j e c t method of NSArchiver class. Once
you have an NSData object, you can place it in a dictionary
with a this case.
You will notice that the dictionary is built up directly with the
_ I D and _ t i t 1 e objects. Dictionaries can only contain a lim-
ited number of types of objects. NSData is among them, but
NSImageRep is not. Therefore, you need to convert the NSIm-
ageRep object to an NSData object before processing it in the
dictionary. This is such a common occurrence--converting a
Cocoa object to an NSData object--that the underlined code
to archive and unarchive the image is boilerplate code. Just
change the name of the variable with the object to be archived.
Java:
Objective-C:
Unarchiving Unarchiving is similarly easy. You do need to
check that you actually have found an NSData object with the
right key in the dictionary. Once you have it, you can safely
unarchive it and coerce it to the type that you know it is.
Java"
Objective-C"
Archiving preserves class information. As a result, w h e n you
unarchive an object, it is reconstituted as a class, and you can
use it. (You may have to coerce it from a generic NSObject to
the object of your type--see the underlined code in the previ-
ous snippets.)
Serializing writes out the information within an object so that
it can be restored later. The methods in the previous section
This distinction is particularly notable in the case of
dearchiving and deserializing. You call the class method
to unarchive
an object; it returns an NSData object. When deserializing an
object, you create the object first and then call that object's
you choose to call the comparable method) to fill the newly
created object with its data.
As the code in this section shows, you can combine archiving
and serializing.
You can dynamically create objects from serialized data. As
with all the code in this section, the following snippets are
boilerplate. Simply insert your class name and the names of
its variables; also, declare dictionary keys for its class name
and the variables.
There are two parts to this process. First, store the name of the
class in addition to the data. In the underlined code of p r o p -
ertyListRepresentation, the name of your object's class
is retrieved and stored in the dictionary that will serialize the
object's data.
On retrieval, convert the class name string to an actual class.
Then create an instance of this class. (The two necessary lines
of code are underlined.) Note that in Java, you need to coerce
the NSObject result of n e w I n s t a n c e to your own class.
This recipe is from the Sketch example, and its use there is
typical. In Sketch, the SKTGraphic object is an abstract class
from which SKTRectangle, SKTTextArea, and others descend.
Java:
Objective-C:
For many objects, this is all that needs to be done. For some
objects (such as NSTextArea), additional data needs to be han-
dled. If you use this architecture, you simply override p r o p -
object has simple data to store (integers or boolean
preferences, for example), they do not have to be archived be-
fore being placed in the dictionary.
Note that the highest-level implementation of methods such
as this create the dictionary and return it. Thus, in SKTGraph-
ic (the root of this class of objects), the dictionary to be used is
created. In the descendant, it is used. Also, note that the
names of these methods are commonly used, but you can
name them whatever you want.
Java:
Objective-C:
Distribution is a similar process. It relies on ports and connec-
tions between ports (see "Tasks" on page 491) so that you can
transfer objects among processes.
Among the most basic programming tools needed to imple-
ment sharing is some ability to copy objects. Copying objects
(cloning them, in some terminologies) is not quite so simple as
you might imagine. Objects often contain instance variables
that refer to other objects or to complex data structures. A
copy of an object needs to handle these embedded objects ap-
propriately; often they need to be copied themselves and ref-
erences to the new objects stored in the copied object.
There is a distinction between shallow copying (cloning) and
deep copying (cloning). A shallow copy is simply a copy of
the object's bit structure in memory; references to objects in
both the copy and the original point to the same objects. Deep
copying makes copies of embedded objects where necessary.
A shallow copy's references point back to the same objects as
the original does, so a change to either the original or the copy
has the same effect on the embedded objects. The NSMutable-
Copying protocol produces such shallow copies; NSCopying
produces deep copies.
In some circumstances, you may decide that the single NSCo-
pying protocol is appropriate to use and that it should pro-
duce shallow copies. Note also that the distinction between a
shallow and a deep copy is clear conceptually, but may not be
so hard and fast in reality. Nothing prevents a copy having
some fields that are deep copies and others that are shallow
copies. If this is the result of carelessness, it's obviously
wrong; however, if the situation justifies it (and it is docu-
mented), there is nothing wrong with it.
Copying is implemented with protocols~NSCopying and
NSMutableCopying. Objects are created by both protocols
and may (or may not) be modified by others. These new ob-
jects are not autorelease objects: You must manage their dis-
posal yourself.
Copying needs to be implemented based on your object's data
structures. A reference to a font, a string, or a dictionary may
well not need to be copied; references to subviews of a view
usually do need to be reinstantiated and copied.
The challenge is actually not particularly daunting if your ap-
plication is well structured; call the superclass's method first
to allow it to do its own work. You probably will have rela-
tively few instance variables that need to be copied.
On a case-by-case basis you will need to decide what to do
about copying state variables. For example, is a copy of a view
to have the same location and selection as the original? Should
its location be slightly offset? Should its location be as it
would be for a newly created view and should its selection be
nil? These are your decisions to make.
Using the clipboard to share information often takes advan-
tage of printing routines to put PDF versions there. As a re-
sult, the clipboard is covered later in this b o o k ~ s e e "PDF and
9
Clipboard Support" starting on page 532 as well as Chapter
27 for more on that topic.
You may never have given much thought to s y n c h r o n i s m ~
the processing of several chores at once. Synchronism didn't
exist on the early personal computers, and even today it is
fairly rare. Multiprocessing, multitasking, and multithread-
ing are all aspects of synchronism: They allow several things
to go on at the same time. When a computer has more than
one processor and has network connections and peripherals
that have their own processors, it makes little sense to hold
everything hostage to a model that handles one thing at a
time.
Synchronism has four principal aspects:
9 A hardware environment in which several things can
be done at once.
An operating system that is designed to manage mul-
tiple processes.
Application software that takes advantage of the hard-
ware and operating system.
Perceptual synchronism which refers to the structur-
ing of an application's interface so that although noth-
ing actually moves faster, it appears to do so for the
user. (The display of progressive GIFs on Web pages
is one such example.)
Cocoa implements the first two. Your concern is with the third
condition: software that takes advantage of all of this. Old-
time programmers who wrestled with mainframes know the
enormous performance improvements that you may be able
to achieve when you use synchronism properly.
Hardware-based synchronism takes
advantage of the fact that a computer (even with a single pro-
cessor) is often waiting for disk reads to complete, printing
jobs to finish, network connections to work, etc. Having hard-
ware components that can work simultaneously is a neces-
sary precondition for implementing any kind of synchronism.
If you have only a single processor and no peripherals, noth-
ing can be done on that computer that is not done by the pro-
cessor: Synchronism is impossible in this case.
Today's computers, of course, present multiple opportunities
for synchronism. Multiple processors within a single comput-
er (not to mention networked computers that can share pro-
cessing chores) allow a high level of synchronism; peripherals
with their own processors and buffers (such as modern print-
ers) allow the main processor not to have to wait for slower
devices.
Unless you are writing a very time-critical application that is
intimately tied to a specific hardware configuration, as an ap-
plication developer you are unlikely to be closely involved
with hardware synchronism. However, the strategies that
you take in implementing application synchronism rely on
there being some form of hardware synchronism (you just
don't know what specifically exists).
kernel) implements as much synchronism as possible.
There are many tricks that can in-
crease the perceived responsiveness of an application. One of
the most common is embodied in progressive GIFs: Start the
response to a command as soon as possible, rather than wait-
ing until all (invisible) processing is complete. Another tech-
n i q u e ~ p r o v e n in much research~is to provide the user with
the ability to control (and terminate) actions that take time. A
user who feels in control of a process will swear that it takes
less time than a process that cannot be controlled.
Here are some strategies for taking advantage of synchro-
nism.
You can increase your application's throughput by interleav-
ing communications calls with your application's code, rather
than doing all of your processing and then transmitting ev-
erything. This means that your total elapsed time of using the
network is longer than if you had waited to handle all of your
communications at once, but as long as the protocol and net-
working software allow sharing, you don't degrade anyone
else's performance. And because at least a certain amount of
the network processing is dependent on remote events, your
computer's processor is likely to be waiting for a significant
amount of time during communications processing. This
strategy is available to you on many operating systems, not
just Mac OS X.
Because Mac OS X provides support
for threading, you can create multiple threads within your ap-
plication. If each thread does standard (or at least similar) pro-
cessing involving computation, memory accesses, disk
accesses, etc., chances are that each thread will periodically
wait for processor, memory, or disk. By having several
threads, you increase the likelihood that one thread's wait
state will coincide with another thread's performance. (You
can also give threads separate priorities so that a less impor-
tant thread chugs along slowly but surely while your higher-
priority main thread does its critical processing as quickly as
possible.)
Threads all share your task's globals. If you are going to use
threads, you will need to consider using locks to protect these
globals from corruption (see "Locking" later on this page). Be-
cause they share your task's globals, the task cannot terminate
until its last thread terminates.
U s e Multiple Tasks You can spin off an additional task to do
processing that is more independent than that of a thread.
Each task has its own memory space and its own globals. As
a result, you don't have to worry about locking shared re-
sources, but you also don't have the advantage of easily being
able to share data. Tasks can be fired off to perform processes
that the originating task no longer cares about (imaging to a
file, communications, etc.).
If you are planning a system for an environment that may
grow in the future, tasks can also position you very well to
work in a multiprocessing environment. Because tasks are in-
dependent, you can distribute them across a network of com-
puters. Even if this is not your environment today, the
architecture presents few problems in the present--and may
provide significant opportunities in the future.
Whatever you d o - - w i t h tasks or t h r e a d s ~ y o u have to banish
the notion (if you still have it) that a single application pro-
gram is in charge of everything.
As soon as you move out of the single-processing model, you
need to manage interactions among processes. In multiuser
databases on mainframes, this has been an issue for decades.
You can take advantage of that experience in designing your
application.
The simplest case is illustrated by what happens when you
see an unusual lamp in an antique store that you cannot live
without but which you suspect (fear? hope?) will not work its
magic on your spouse, partner, or family. If you run home
and drag the appropriate people back to the antique store, the
lamp may have been sold to another sucker. You can prevent
this by asking the dealer to hold the l a m p - - b u t that puts the
dealer in the rather tricky position of possibly turning down a
sale just so that you can come back and say no.
A lock is basically a hold on all processing~except for that of
one thread. In the lamp example, if you could convince the
dealer to place a lock on the lamp, no one else can buy it until
you release your lock. (Databases use sophisticated locks, as
do antique d e a l e r s ~ y o u r agreement may be that the dealer
can't sell the lamp, but that it can be shown without commit-
ment to prospective buyers.)
Locks are whatever you say they are. Although locks are often
associated with resources (printers, for example) and with
data (a customer record, for example), the Cocoa lock mecha-
nism has no intrinsic meaning. You can lock a method, which
you might do if you know that a call to that method will make
heavy demands on the computer's resources. Although you
allow users to have many windows open at the same time and
to work with many images, perhaps you will lock the method
that does heavy image manipulation so that if a user decided
to reimage several images at the same time, the imaging code
would be locked to prevent crippling the system.
NSLock The heart of the locking mechanism is the NSLock
object. You create lock objects fairly early in your applica-
tion~certainly before you spin off threads. (If you don't spin
off threads, you have no reason to create locks.)
A descendant of NSLock is NSCondition-
Lock. This is a more sophisticated lock: It has a condition val-
ue (an int) that you can set. You can request that the lock be
granted if that condition has a certain value. By defining con-
stants with meaningful (to you) values, you can add a great
deal of sophistication to your locks.
You normally set the lock's condition value by using i n i t -
Beware of getting too sophisticated with your conditions if
you are not experienced in this area. In particular, conditions
that themselves involve other locks can bring you to grief. A
thread that requests a lock is blocked from further execution
until that lock is granted, which means that you can easily get
yourself locked out from everything.
In the cases where you do need to request multiple locks with-
in a single thread, use NSRecursiveLock.
A thread is blocked when it requests a lock
until that lock is granted (unless it uses the timeout feature in
l o c k B e f o r e D a t e ) . If methods within your thread might at-
tempt to acquire a lock that your thread has already acquired,
you might be in the position of nesting your l o c k s ~ a n d the
second lock will never be granted and your thread will be
blocked from further execution because the first lock cannot
be released. In this case, use NSRecursiveLock rather than
NSLock. It brings a little more overhead with it, but it pre-
vents you from accidentally locking yourself out. (These rules
about locks apply to individual locks. If your thread acquires
five separate locks~five separate instantiations of N S L o c k ~
you don't have to worry about locking yourself out.)
NSLocking The NSLocking protocol defines lock and unlock
methods that you use to manipulate NSLock objects. As noted
previously, the lock method of the protocol blocks your
thread from further execution until the lock is granted. You
are almost always better off to use the NSLock 1 ockBe f o r e -
Da t e method.
For unlocking, however, the u n l o ck method is used in all
cases (except for w h e n you need to set a condition for an
NSConditionalLock).
Each task starts off with a single thread. If you want to create
additional threads, you use the NSThread object. Threads
share your task's global variables. If you are going to be creat-
ing locks for data or processing, create them in your task's
first thread before creating additional threads.
Tasks have more independence than threads; they live in their
own address space and function independently. You don't
use locks if you are sharing resources among tasks, because
locks need to be in a common address space. A task runs in its
own environment: a directory, which includes standard in-
put, output, and error files; and other implementation-specif-
ic variables. When you create a task, it inherits your own
task's environment unless you explicitly change its environ-
ment in whole or in part. This must be done before the task is
started; thereafter, it is responsible for making any changes in
its environment.
NSConnection lets you share objects between threads or tasks
whether on the same machine or on different hosts.
A connection consists of two NSConnection objects, one in
each thread that is communicating with the other. Each con-
nection has a send and receive port; they mirror one another
in the two threads (that is, the send port in the NSConnection
of one thread is the receive port in the NSConnection of the
other thread).
You can use NSConnection to share distributed objects be-
tween threads and to send messages back and forth. From
your point of view, the connection's root object is what is seen
by others; the connection's root proxy is what you see at the
other end of the connection.
The shared environment of Mac OS X processing allows you
to take full advantage of the modern OS and of sophisticated
contemporary hardware with multiple processors and pe-
ripherals with their own processors and memory. If you come
from the hoary mainframe world, this is second nature to you.
If you have lived all of your life on a personal computer, how-
ever, you may not realize the power of these features. There is
no doubt that the future will bring more processors, more
connectivity~and more opportunities for applications that
are prepared to live in this world.
Nothing requires you to use tasks and threads, but becoming
familiar with them and using them where appropriate pre-
pares you for the most sophisticated system designs of the fu-
ture.
This chapter has explored various aspects of sharing of data,
including sharing it over time and space with archiving, seri-
alization, and distribution. Synchronism involves sharing re-
sources~particularly m e m o r y ~ a n d it, too, has been covered
here.
These are relatively low-level concerns. That is, you use the
methods shown in this chapter, but you rarely do more than
reimplement them as boilerplate code. Instead, you focus at
the next highest level of data: documents and files. They are
covered in the next chapter.
This Page Intentionally Left Blank
Most computer users work with files on a routine basis. Whether
they are word processing documents, image files, or spreadsheets,
the basic paradigm of the personal computer remains very much doc-
ument-centric.
Recently the Internet and local area networks have created a new
breed of user who does not focus on documents. For this user, email
messages, Web sites, and databases supplant paper surrogates. Still,
a lot of work (and play) depends on a user entering data, modifying
it, saving it, and then opening it at another time or sending it on to
someone else.
Cocoa supports a robust document model. Like the frameworks of
Carbon, the document model handles much of the work for you. In
any of these environments, you may never need to execute r e a d or
wr i t e statements.
This chapter provides an overview of document handling on Mac
OS X and Cocoa. In particular, you will find sections on:
9 Working with document-based architectures
9 Implementing documents and views
9 Saving and restoring documents
9 Managing changed documents (using Undo and Dirty )
The advent of the personal computer and its widespread use
in offices gave birth to the document-based architecture that
is so common today. Before then, computers had worked pri-
marily with data files located on various storage devices
(mostly of a magnetic nature). By the 1970s, databases started
to replace the flat files, but not much else changed. Typical
batch processing on mainframes consisted of two types of op-
erations:
0 Reading a record from an input file, doing something,
and then writing it out to the same or a different file.
0 Reading a lot of records from one or more input files,
doing something, and then writing out a s u m m a r y or
synthesis to a printer of another file. (Payroll and in-
voicing programs are examples.)
On personal computers, the model is very different: The en-
tire contents of a document are read into memory, things hap-
pen, and then everything is written back out. On mainframes,
the concept of reading everything into memory before work-
ing on it would be considered absurd.
The consequence of this is that the normal processing for a
document-based application consists of three tasks:
1. Reading a document and displaying it
2. Allowing the user to do something with it
3. Writing it out
Document support in Cocoa addresses all three of these tasks.
While the first and third are obvious, it is not always clear that
the document supports the second task. Undo and keeping
track of when a document needs to be saved are tasks that the
document needs to provide in a Cocoa application; therefore,
the document is heavily involved in all three of these tasks.
Some people find the model-view-controller architecture use-
ful in helping them plan and design applications. A variation
on that architecture is helpful to other people. In it, the two ba-
sic components~models (data and processing logic) and
views (visualization and interface)~are used. Rather than
identify a third component (controllers), the concept of con-
trollers is used to identify objects a n d / o r methods of views
and models that provide bridges to other controllers and thus
from models to views, and vice versa.
This revision to the model-view-controller architecture is
helpful in looking at documents, since it maps absolutely to
documents as they are used in Cocoa (and most other frame-
works). Think of a document as a model object; it uses control-
ler objects and has its own controller methods. It is those
controller objects and classes that can communicate with the
view that displays it.
Likewise, a view object uses controller objects and has its own
controller methods, which it uses to communicate with docu-
ment (model) controller objects.
Whatever your feeling about architectures and theories such
as these, remember that their purpose is to help you under-
stand code that you read and to help you write better code.
The architecture, paradigm, or theory is a tool to help you, not
a goal in and of itself.
As with so much of Cocoa, implementing documents and
views consists of a great deal of boilerplate code. The general
outlines are provided in this section.
There are three sections of code"
0 Document headers: the source code basics you need to
declare
2. Constructors: creating the document
3. Window controllers" displaying the document
The start of the Diary header files is presented here. The
Project Builder templates produce similar code, but you need
to insert your own variables.
The standard import commands for the AppKit and Founda-
tion frameworks are always required. If you are implement-
ing a document-based application, you must subclass
NSDocument; the Project Builder template does this for you.
Next, declare your Interface Builder outlets. Note that in Java
they are private; in Objective-C they are identified as IBOut-
lets. The list of outlets here must match the list in Interface
Builder to which you have attached interface elements. Fur-
thermore, the types should match (i.e., your NSTextField in
your code must be attached to an NSTextField or descendant
thereof in Interface Builder).
Declare variables that you use. As described previously, you
may wind up fishing data through a variety of subsidiary ob-
jects. In the Diary example, a single data member belongs to
the document class: a DiaryData object (underlined). That sin-
gle object has its own data (such as t i t 1 e), and an array of
DiaryEntry objects. Accessors let you fish down to the actual
data through each level.
Finally, declare strings that you may need for notifications,
dictionary support, and the like. In Java, there is only one file,
and these strings are declared there. In Objective-C, the
strings are declared at the top of the .m file (the other headers
are in the .h file).
Java:
Objective-C:
You must provide constructors for your document object. You
do not call them, but they must be ready to be called by Cocoa
at appropriate times. In Java, constructors are not inherited,
and you need a constructor for each w a y in which your docu-
ment can be created (as a blank document, with a file name,
and from a URL).
Objective-C does not require this; your single i n i t method is
called in all cases. But in Objective-C, you do have to worry
about m e m o r y management. In Java, the new function creates
a subsidiary object (DiaryData). In Objective-C you use a l -
l o c to create an instance of DiaryData. Because you have al-
located it, you need to provide a method to
deallocate it (and any other objects you have allocated).
All of these methods are called automatically, but you must
implement each of them for yourself. Also, note that the inher-
ited method is called in every case.
Java:
Objective-C"
Along with constructors, you need to provide the framework
with the name of the nib file to be loaded with your document.
Following are the methods. If you change the name of your
nib file (and you might prefer not to have the generic Project
Builder MyDocument default), you must change the under-
lined code.
Java"
Objective-C:
If you have any initialization to do (such as setting fields in
the view of your document), you do it in an override of w i n -
In Diary, the
method is called. In the examples, in-line
You almost always override this method. Even if you start off
by not doing so, you should put an override in because you
will probably need it as your project grows.
Java:
Objective-C:
The methods shown here need to be overridden to implement
saving and restoring data. The code here is from Diary and is
based on Sketch; rather than use in-line accessors, methods
are called to load and unload the data.
The architecture involves taking your document's data and
converting it into an NSData object. You can do this in any
way that you w a n t ~ a r c h i v i n g , serializing, or some other
manner. The methods that you write (called l o a d D i a r y T o -
NSData object that contains your data. It can be any type of
object that you want (here it is a dictionary).
This is where most of your work occurs. It should be familiar,
however, given that it has been described many times:
1. Create a dictionary.
0 Set keys and values for basic information (a version
number and an archived PrintInfo object).
Q Call a method to move data from your interface to in-
ternal variables.
Q Pass the dictionary into a method that loads the inter-
nal values into it and returns it.
Depending on your application's design, step 3 ~ m o v i n g
data from the interface to internal v a r i a b l e s ~ m a y be per-
formed elsewhere. It often makes sense to make the moving
of data the last step of a previous process rather than an inter-
mediate step in the data writing process.
Java:
Objective-C:
NSDocument automatically sets up the architecture to man-
age multiple document types. This is handled with data rep-
resentations. Each data representation is identified with a
string, and depending on which one is presented, you provide
the appropriate data.
The PrintInfo object and the undo manager object are com-
mon in document-based applications. If you do not support
printing or undo, leave them out (and shame on you).
Java:
Objective-C:
- (B00L) l o a d D a t a R e p r e s e n t a t i o n : (NSData *) d a t a
As you can see from the underlined code, the DiaryData ob-
ject is created, and then its u n l o a d F r o m D i ct i onary method
is called. It contains a very standard code: It unloads two sim-
ple variables (Diary owner and title), and then it creates an ar-
ray filled with objects--the individual Diary entries. Here is
that code:
Java:
Objective-C"
If you use the default undo mechanism in Cocoa, your docu-
ments are automatically dirtied for you. The dot appears in
the center of the close button to indicate unsaved changes,
and if the user tries to close the document, a sheet prompting
for saving is displayed.
While you can implement undo/redo in very complex ways
(and you can also implement dirtying of documents yourself),
the process is very simple if you use standard code. The heart
of the code consists of the snippets shown here. When a vari-
able's value is changed, it is called. It assumes that the object
in which this code resides has a method that returns an undo
manager. NSDocument has such a method, so your document
will have it, too. If this code is called from another object, it
will need a reference either to your document or to its own
undo manager.
If you use the two-step architecture of accessors (which do not
dirty documents and cannot be undone) and changers (which
do dirty documents and can be undone), the logical place for
this code is in the changers that change your variables. If you
expose them as actions, you can link them to interface ele-
ments in Interface Builder. This is the issue that was alluded
to earlier with regard to w h e n to move data:
You can leave data in interface elements and move it
into internal variables only w h e n you need to reuse
the interface elements or dispose of the data.
You can immediately move the data into internal vari-
ables as soon as editing is complete (that is, w h e n an-
other interface element is clicked).
The second mechanism makes it very easy to implement
u n d o / r e d o for individual elements. The second mechanism is
a very elegant way of producing a single event to Undo or Re-
do. Depending on your application and the nature of the data,
you can choose one or the other. You can also group u n d o /
redo actions to have the best of both worlds.
This section gives the Diary example code that registers the
undo for changing an entry title. There are three steps to the
process:
1. Create the basic actions.
2. Register the undo actions.
3. Clear the undo stack when you are done.
This is an example of a changer from Diary. It changes the Di-
aryEntry title; it is the action that is connected to the interface
title field. Note that it checks whether the value of that field is
equal to the current value of the title; if not, it calls a second
method. By convention in Diary, c h a n g e . . . b y S c r i p t meth-
ods are changers that can be invoked from the user interface--
as here--or via AppleScript. Thus, the check for the interface
value is omitted.
Java:
Objective-C:
When you perform an undoable action, you need to register
the undo method and value with the undo manager. If the
user chooses Undo from the Edit menu, the method and value
you have registered will be used.
Java:
Objective-C:
(that is, the before image of the data). This method is particu-
larly useful when there are multiple arguments to be passed
in the callback method and when non-objects are involved.
At an appropriate moment (such as when the document is
saved), you clear the undo stack.
Java:
Objective-C:
You need to update the document's change count when it is
dirtied and then again when it is saved. NSDocument itself
does most of the processing for you. You can override update-
ChangeCount if you want to do additional processing at that
time, as shown in the previous section.
With documents and files, you can save and restore data be-
tween different executions of your program. The process in-
volves not only reading and writing them, but also flattening
and then restoring the objects they contain. Furthermore, you
need to implement support for dirtying documents and undo-
ing (or redoing) commands that change them.
The end of the development process is in sight: Menu com-
mands are one of the last parts of the graphical user interface
that you need to implement.
This Page Intentionally Left Blank
Menus are one of the most basic parts of the graphical user interface.
In Cocoa, they are easy to set up; in MacApp Carbon-based applica-
tions, they are nearly as easy.
The Aqua Human Interface Guidelines (available on Apple's
Web site via a link on http://developer.apple.com/ue/) provides the
last word on menu styling and placement. In short, the guidelines
request that you keep your menu items short, absolutely clear, and
organized in a logical manner. Long-standing arguments about the
proper use of menus have simmered down, and the consensus is that
menus should be short (a dozen items is plenty), and that hierarchi-
cal menus (submenus) can be overused with extraordinary ease.
This chapter is brief in part because menus are so easy to implement
in Cocoa, but also because menus no longer have the role they used
to have in the interface.
The original Macintosh (and other graphical user interface
systems) consisted of relatively small screens. The routine for
users was simple: Select something in the active window, then
choose the menu command to act on it. With small screens
and smaller windows, this was about the extent of the inter-
face.
With the advent of larger screens and more powerful proces-
sors, windows began to accumulate additional controls. If
you compare screen shots of modern software with that from
10 or 15 years ago, you will be struck by the proliferation of
controls everywhere: in windows, tucked into corners of
scroll bars (placards), in palettes, and now in Mac OS X in
toolbars and drawers.
What this means is that the controls and commands that a
user needs to use are located as close as possible to the focus
of attention. For most users, the focus of attention is rarely at
that menu bar at the top of the screen.
If you are designing applications in the old style, think about
changing your point of view. Although it is not part of Ap-
ple's guidelines, you can consider menu commands as sec-
ond-class commands, used only when the right c o m m a n d is
not available. They also function as a useful backup mecha-
nism for users who do not know where all the close com-
mands are located (or even that certain interface elements
hide commands).
Naturally, all of the standard menu commands must be im-
plemented (Cocoa does this for you). In addition, all of your
application's primary functionality should be exposed in the
m e n u bar. But it is no longer necessary for every bell and
whistle to have its own m e n u command: Your array of inter-
face choices is much greater than it was before.
So not only should you keep your m e n u commands terse and
clear, but you should also not clutter your m e n u bar with
commands that people will not use. Watch how you use your
Macintosh, and you may be surprised. For most people, the
experience of using m e n u commands with the mouse is get-
ting less and less frequent. Keyboard equivalent-driven menu
commands, however, remain at least as popular as ever.
One of the consequences of this proliferation of controls is that
m e n u commands are present in m a n y places and in m a n y
configurations. For example, a placard in a scroll bar might let
you adjust a view's zoom factor (as in TextEdit). You might
also be able to access the zoom factor via a hierarchical m e n u
in the m e n u bar and in a contextual menu. In each location,
the adjacent controls are different; this allows the application
designer to have several logical groups of the same com-
mands.
The Dock and the Finder toolbar are perfect examples of this.
You can put a folder or document into the Dock as well as into
the toolbar; w h e n you want to return to Current Projects, you
can get there with one click depending on which context is
most convenient at that moment.
This is what users expect today. The m e n u bar as the sole
source of c o m m a n d s ~ m u c h less organized the w a y the de-
veloper w a n t s ~ i s not the only game in town.
Contextual menus appear w h e n a user CONTROL-clicks on an
interface element to which such a m e n u has been attached.
You create each contextual m e n u by itself in Interface Builder,
and you attach it to an interface element's m e n u outlet. Each
view (and thus each interface element) has its o w n m e n u out-
let.
Contextual m e n u c o m m a n d s should be n a m e d with the same
names as m e n u bar commands. A l t h o u g h the Finder imple-
ments a special Show Package Contents c o m m a n d in the con-
textual m e n u for packages, such an interface choice is
unusual.
Remember, too, that contextual m e n u s appear just that w a y ~
in a context. Half a dozen particularly relevant m e n u com-
m a n d s are sufficient. Users k n o w the m e n u bar is there if they
need more.
The icons in the Dock s u p p o r t p o p - u p m e n u s that are similar
to contextual menus. These m e n u s contain a combination of
c o m m a n d s from the application that is r u n n i n g and from the
Finder.
You can place c o m m a n d s from your application in the Dock
m e n u that pops up w h e n a user holds the m o u s e d o w n over
your Dock tile. These c o m m a n d s appear at the top of the
m e n u (the standard Finder c o m m a n d s are below them).
There are three steps involved in implementing application
Dock menus:
1. Create the menu using Interface Builder.
2. Connect it to your NSApplication object.
3. A d d it to your application's info.plist.
Creating the Menu Like most interface elements, you can use
Interface Builder to create your Dock menu and place it in a
nib file. In view of the fact that the Dock menu may be access-
ed in very different ways from your standard application
menus (such as w h e n your application is in the background),
it is best to create a new nib file for your Dock menu.
Create the nib file in Interface Builder. Save the nib file, and
add it to your project. If you have launched Interface Builder
from Project Builder with your project open in Project Builder,
you will be prompted to do so. If not, you must manually add
the file to the project using Add File in the Project menu.
With Project Builder, add the nib
file to the info.plist. In the Targets pane, select your applica-
tion, then choose the Application Settings tab. Click the Ex-
pert button, and then add a sibling to the property list. It
should be named AppleDockMenu, and its value is the name
of your Dock nib file (without the .nib suffix). (There is more
detail about updating the info.plist in "Property List Settings"
starting on page 553.)
You can also add an NSApplication delegate that implements
Menu* object which is the application's Dock menu. If you use
this method, you can dynamically change the items in the
Dock menu.
From the bottom up, these are the Dock m e n u commands.
If an application is running, its Quit c o m m a n d is the
bottom c o m m a n d in a Dock menu. If the user OPTION-clicks
on the Dock icon and the application is running, this changes
to Force Quit.
You can use this little tidbit in your documentation and on-
screen assistance. It is much better for a user to know that if
there is a problem the one application can be stopped than to
use a three-key combination to bring up a Force Quit w i n d o w
in which a different application could accidentally be termi-
nated.
S h o w in Finder This command opens a Finder w i n d o w and
locates the application or document that the Dock icon repre-
sents. It is available for all Dock icons.
When an application is running, the Keep in
Dock c o m m a n d is added to the menu. All running applica-
tions have icons in the Dock, and it is frequently convenient
for users to request that they remain there for future use.
You cannot "help" the user out and force your application's
icon to remain in the Dock.
For running applications, the open w i n d o w s that
have been added to the bottom of the application's W i n d o w
m e n u are listed. The other W i n d o w m e n u commands are not
shown.
This chapter is short because so much of menu command pro-
cessing is done for you. In Cocoa, you declare the action meth-
ods that will implement menu commands, and just link them
to the commands themselves in Interface Builder.
Carbon is almost as easy to use, but you do have to handle the
connections yourself within your code. Of course, if you use a
Carbon framework such as MacApp or PowerPlant, that is
done for you automatically in most cases.
The last general function for most applications is p r i n t i n g ~
the topic of the next chapter.
This Page Intentionally Left Blank
Printing in Cocoa (as in MacApp and most other frameworks) is a
simple operation for you to implement. At its most basic, you take a
view that is displayed and pass it to a method that redraws it for the
selected printer. The standard page setup and page layout settings
are managed by the framework.
This works for small views where a simple copy of the screen image
is sufficient. It breaks down when you want the printed version to be
different (with timestamps, for example, or headers and footers that
do not appear on the screen). In that case, you create a separate view
just for printing and place your data into it. If you have set up your
application well, the data (model) and the view are as distinct as pos-
sible; as a result, it should be a simple matter to redraw the objects
in a new view.
Mac OS X supports PDF print previews. When these are required,
you can implement them with a special override if needed.
Although the standard page setup and printing dialogs are usually
satisfactory, you can also extend them.
Printing is handled by the NSPrintOperation object. You are
responsible for creating it, associating a view with it, and run-
ning it.
The simplest form of printing involves overriding the print
method of a view. If you do so, printing will just work for that
view. Here is the code:
Java:
Objective-C"
Of course, most of the time, you do not want to print a single
view. Rather, you want to print the contents of a window. Be-
cause printing starts from a single view and proceeds through
its subviews, you will soon realize that if you place a view at
the back of each of your windows (possibly containing a back-
ground pattern), you will have the view that you need for
printing.
If you have a document-based application, you override the
view. (If you are printing a simple view, as in the previous
case, you might not want to do so. The print panel allows us-
ers to select a printer--usually a good i d e a - - b u t it also lets
them choose a page range, which is irrelevant in some cases.)
Java:
Objective-C:
If your view contains scrollers, the results of printing it may
be surprising. You actually do not want to print the scroller in
m a n y cases; rather, you want to print the entire contents of the
view contained within i t ~ n o matter how long it is.
One way of handling that is to implement a per-page view in
your application (TextEdit does this). Another w a y is to refor-
mat the contents for your printing view.
If you want to remove scrollers from your view so that vari-
able-length text views can be printed, or if you want to add
headers or footers, you need to create a special view for print-
ing.
In the case of variable-length text fields, the problem is not
particularly difficult, because at the moment you are printing
the view, the field is not variable length. You know exactly
how big it is. You can create a view (or resize one) to be exact-
ly the size that you need for printing.
The Sketch example creates a view for printing its objects us-
ing the following code. If you need to do this, you need only
do two things:
1. Create a rectangle the size of the view to be printed.
What this size is and how it is calculated are up to you.
0 Create an instance of your own view and initialize it
according to your own application's code. You may
add other objects to it; you also might subclass your
normal view to automatically add objects for printing.
In the Java example, these two steps are done in two lines of
code; in Objective-C, they are done in one line. You can use ei-
ther structure in either language. Then (unless you have
changed variable names), this code will work for you.
Java:
Objective-C"
Print panels are the sheets that let you choose a printer, select
a page range, and cancel the whole operation. They are dis-
played by the print operation object that you create and run.
Normally, the default panels are just fine. However, if you
need to extend the print panel, create a view and add it to the
bottom of the default print panel. You do so with the follow-
ing code:
Java:
Objective-C"
You also can set your own print pane within the print panel.
This is preferred, because the basic look of the print panel will
be preserved.
Print info is the collection of data that is set using the Page Set-
up command. Your application has a print info object that it
uses for its printing.
get the object. If you save data for your application (whether
in a document or not), you should get the print info object and
save it as shown here:
Java:
Objective-C"
This is the methodology described in Chapter 23. There are
other ways to store the print info object, but all that matters is
that it is stored.
Setting the print info object is also possible, but it has to be
done carefully. You may prefer to add to the default print info
dialog by calling the se t A c c e s s o r y V i e w method of NSLay-
out. Once you have done this, your application's print info ob-
ject will have the data that you have specified in your view
(and that your user has selected).
Java:
Objective-C:
It is often the case that you need to produce a PDF version of
print operation that you can then run to transform a view into
PDF and returns it in an NSMutableData object. You can then
place that on the clipboard as you will see in next section.
Here is the basic code to generate the PDF:
Java"
Objective-C"
U s i n g that p r i n t operation, y o u can then p r o d u c e a PDF im-
age that y o u can place on the clipboard or use as a print pre-
view. Here is h o w Sketch does it.
Java:
Objective-C:
In Mac OS X, the print architecture supports not just printing
but also PDF generation. Printing is the last general-purpose
application technology described in this book. The remaining
chapters deal with specialized features of Mac OS X that you
may or may not use.
For starters, the following chapter deals with human interface
devices such as those used in games.
This chapter contains essential information for game developers, but
its subject matter goes far beyond games. Imagine for a moment a
game in which you can use your computer to manipulate a wide
range of devices whose controls and behavior you see on the screen.
Perhaps you decide to try gene splicing or building DNA in a biol-
ogy simulator game.
The only problem with this scenario is that it is not a game. Com-
puters are constantly used to manipulate mechanical devices, and
they receive input not only from the mouse and the keyboard, but
also from a variety o/control and graphical inputs~joysticks, dials,
and the like.
The Macintosh computer has always been prominent in research~
particularly in biomedical research and in space. In large part, this
is because many research projects require scientists to combine com-
puter programming skills with other, domain-based skills. The Mac-
intosh has always provided advanced programming tools, and it
continues to do so with Mac OS X.
Managing the human interface devices that run games and scientific
experiments requires interacting with the basic hardware governed
by the kernel. This chapter shows you the highlights of the Human
Interface Device (HID) manager, which will be your constant com-
panion.
Also in this chapter, you will find information about NSMovie and
NSMovieView. These are the Cocoa classes that let you play and
manipulate QuickTime movies.
Finally, the correct way to handle immersive interfaces using the
full screen is described.
One of the key features of Mac OS X and its kernel design is
that you are insulated from the hardware. That is all well and
good until you actually need to communicate directly with
hardware. The key to this on the Mac OS X side is the commu-
nication concept of a Mach port in the kernel; on the device
side, it is the USB standard that comes into play.
USB devices are categorized into a variety of classes, includ-
ing hubs, mass storage (disks), monitors, printers, power de-
vices, and human interface devices. This last category
includes everything from keyboards, trackballs, and writing
tablets to joysticks, knobs, switches, throttles, and steering
wheels.
These devices are used to control games as well as equipment
connected to the computer. They are also used for standard
and adaptive input to applications and the operating system
itself.
Each HID device contains usage information that is defined
for all USB HID devices in usage tables that you can down-
load from http://www.usb.org/developers/hidpage.html.
A device (such as a keyboard or trackball) can be defined by a
combination of a usage page and usage number, which forms
a unique value.
Interacting with HID devices is easy with the HID Manager.
A detailed example is given in the kernel documentation
mentioned above. Here is the summary of key steps in the
process.
The code in this section is C++ Carbon code. The initial imple-
mentation of the HID Manager on Mac OS X is in that envi-
ronment.
Mach ports are an abstraction of the communication channels
for your devices. You can get a Mach port by calling the fol-
lowing function:
You will use ma s t e r p o r r throughout your program.
The following code is not particularly simple, but it is called
every time you w a n t to find HID devices on the port. You do
not have to vary it.
The heart of the device search is a call to
You construct the dictionary to find all HID devices with this
code:
If the iterator is not on return, and if is
kI ORe turnSucces the iterator to loop t h r o u g h the
s, you use
devices to find one that you are interested in.
W h e n you have found a device in which you are interested,
you create an interface to it in order to use it. To do this, you
run the iterator that was returned in the previous step:
You use this same code in all cases. The only customization is
the test to see if you w a n t to use a specific device. If you do,
On the other hand, if you are searching for a single device,
you can use the in-line code as it is here.
Once you have a device (or an array of devices), you open it
(or them):
The name of your device interface needs to be passed in twice
as shown in the underlined code. If you use a different name,
change this.
Use g e t E l e m e n t V a l u e to get the value of any element in the
device.
The two keys to this are the constant identifying which ele-
ment you are interested in and the h i d E v e n t . This is used
throughout the HID Manager and is defined as follows:
HID events are element values associated with a time. The el-
ement values are stored in the cookie within the event itself.
You can use the HID Manager to retrieve such events. You
also can use it to create queues into which streams of events
are placed.
At this point, you have the mechanism in place to access any
HID device on a USB port and to get any of its data using the
g e t E l e m e n t V a l u e method.
When you are finished, close the device and release the inter-
face:
Make sure to call the following function:
Although the data structures for HID devices include space
for serial numbers, these rarely are used. As a result, appar-
ently identical devices can appear.
Beecause you can plug and play USB devices, it is possible for
a user to unplug a joystick or other HID device, plug it in
again, and discover it will--or will n o t ~ a p p e a r as a new de-
vice.
The IO kit uses the following rule in this case. A device that
appears on the USB bus in the same location as an apparently
identical device (same model, manufacturer, name) is the
same. Any difference causes the IO kit to think it is a different
device. Thus, if your joystick is not responding properly and
you unplug it, blow on the connector, and then plug it back in
(a typically useless operation), it will appear as the same de-
vice. If you plug it into the USB hub on your display w h e n it
had been plugged directly into the computer's USB port, it
will appear as a different device (although it is actually the
same).
NSMovie wraps a QuickTime movie. It is not a w r a p p e r for all
of QuickTime, but some of the QuickTime code is located
here.
NSMovie is the wrapper for the movie itself. Note that the
constructors in Java and Objective-C are slightly different. Al-
so, in Objective-C, you can get a reference to the QuickTime
movie itself on which you can use the QuickTime calls direct-
ly. That reference is not available from Java.
The constructors and inits create a movie in one of three ways:
0 An empty movie (Java) or a movie from a QuickTime
movie pointer (Objective-C).
2. A movie from the clipboard (pasteboard).
3. A movie from a URL. For now, that URL must be local
(e.g., f i l e : / / / u s e r s / j f e i l e r / m o v i e s / c a t . m o v ) . The b y -
R e f argument determines how the movie will be ar-
chived if you choose to do that. If byRe f is true, the
URL (not the movie) will be archived. If it is false, the
movie (not the URL) will be archived.
Java:
Objective-C:
NSMovieView is a standard view in Interface Builder. It in-
cludes the most common commands that you need for a mov-
ie"
Note that the movie controller itself is normally used for nav-
igation, so you rarely need to use g o T o B e g i n n i n g and such.
What is important to note is that NSMovieView supports the
clipboard so that users can copy and paste movies into and
out of your application's NSMovieView objects.
Games typically take control of the entire display, banishing
m e n u bars, the desktop, and all other elements. Movies also
sometimes have full-screen interfaces.
You do not write to the screen buffer on Mac OS X. To capture
the full screen, you use a pair of methods in Carbon. (You
must include the QuickTime framework in your project.)
The first method takes a host of arguments, but you can pass
NULL and zero for m a n y of them.
The WindowRef (fullScreenWindow) is created and re-
turned by the method call; you can use it elsewhere in your
program. For example, if you receive an application deacti-
vate event, you should hide the w i n d o w with
The pointer (stateToRestore) is a pointer to any data struc-
ture (or NULL) that you want. It is returned to you w h e n you
call E n d F u l l S c r e e n . Nothing is done to it in the meantime.
The last argument in the example shown here is a constant de-
fined in QuickTime. Here is its definition:
Finally, you end full-screen mode with a call to the following
method:
As noted previously, you get your own pointer back with
whatever information you placed in it. The second parameter
can be nil (and often is).
The range of HID devices is vast. While many are used today
for gaming, a quick glimpse at the header files will show you
that telephone, set-top boxes, and a wide array of devices not
yet deployed can be supported with these interfaces. Mac OS
X is ready.
This Page Intentionally Left Blank
Services are one of the most useful features of Mac OS X. They move
the concept of the shared clipboard far beyond its simple cut-and-
paste stage. They can expose small (or large) pieces of an applica-
tion's functionality to the world. This matters to you whether your
application is destined to become a client or a server of a service. For
example, if your application occasionally needs to perform some
rather routine operation, you can rely on a service to provide that
functionality and not write it yourself.
On the other hand, you may have an application that does one thing
very cleverly; you can package your particular expertise as a service
and let people incorporate it into other applications. Far too many
great ideas for software have foundered when their developers have
realized that to bring them to market they need to implement and re-
implement a host of surround features that they have no interest in.
For all this, services are remarkably easy to implement in Cocoa.
Note that services rely on the object that is known to users as the
clipboard and to programmers as the pasteboard. As its program-
matic name is NSPasteboard, that terminology is used in this chap-
ter. In describing it to users, you should refer to the clipboard.
When you copy data to or from the clipboard, its type (text,
picture, and so forth) has always been copied with it. Appli-
cations have been able to check whether they can handle clip-
board types before copying information from it. In this way,
applications can copy and paste their own data types in addi-
tion to the system data types.
Services rely on this mechanism, but they extend it. A service
can be thought of as a round-trip to the clipboard from within
an application. Typically, here is what happens:
0 You select something (such as text) in your applica-
tion.
0 You choose a service from the Services submenu of the
application menu.
0 The data is copied onto the pasteboard from your ap-
plication.
0 The application providing the service is launched, if
necessary, by the operating system.
0 That application receives the data from the paste-
board.
0 It does something to the data, and places it back on the
pasteboard.
0 The data is returned to your application, where it re-
places the selected data from step 1.
In this way, a sentence can be capitalized by a service, or a
word can have its spelling replaced (the systemwide spell
checking is implemented by a system service in Mac OS X).
Once you have set up a service, all of this happens automati-
cally. If you use Cocoa, you already are a client of services
where appropriate (for example, services involving text are
available when you click in a text field or text view).
That pattern has variations that lead to two other types of ser-
vices:
Input-Only Services Stickies are an example of such a service,
as is Mail. In each case, you highlight some text. When you
choose the service, it is copied to a new sticky or placed in the
address or text of a new mail message. Nothing happens to
the selected text in your own document.
Mac OS X uses the information you provide in your applica-
tion's property list to set up the Services menu (that informa-
tion is described in "Property List Settings" on page 553). It
scans that information for all applications in standard loca-
tions to build the menu w h e n you log in.
Standard locations are defined as the Applications folders at
your computer's root, in your home directory, and in the Net-
work domain. If your application is not located in one of those
folders, it will not be scanned and will not be available as a
service no matter what you do. Remember this w h e n you test
your application: You will have to move it to your Applica-
tions folder to test it.
This scanning happens at log in time. That means that you
have to log out and log in again to see your service in the Ser-
vices menu. You can make modifications to its code once it is
in the menu without logging in again.
It is interesting to note that users and many developers really
are intrigued with the idea of small, special-purpose applica-
tions. At the same time, what is on the market tends to be
large, monolithic applications. Users want them, too. (You
have only to look at the Project Builder mailing lists at Apple
to see how many new features are requested for that applica-
tion.)
Services offer a w a y to eat this particular cake and have it, too.
Because the business model of commercial software changes
at a glacial rate, many of the opportunities for services are
within organizations such as corporations and schools. Be-
cause services can be so narrowly focused on a particular task,
they can be small. Designed to be plugged into a variety of ap-
plications, they need not be particularly complicated to write.
They should also be relatively inexpensive, and the combina-
tion of low cost to produce and low price to sell should still al-
low for a profit. (At least that is the theory.)
Many services (like much software in general) are provided as
shareware and even freeware. Because services are focused so
tightly on one task, it can be less risky to use them than other
software from sources you may not normally deal with. Re-
member that a service is using a copy of your data: You are
not entrusting your data to an application that will store it in
a proprietary format that you cannot get to.
Setting up a service requires making some entries in the prop-
erty list (info.plist) for your application in Project Builder and
then writing some code.
Start by going to the Expert button in the Application Settings
of the Target pane for your application as shown in Figure 27-
1.
In the scrolling list at the bottom, select any item, and then
click the Create Sibling button to create a new entry at that
level. Name it NSServices as shown in the figure.
The pop-up menu to the right of the name is initially set to in-
dicate that the new entry is a string. You must change it to an
array to work with it further. As Figure 27-2 shows, once you
have set it to an array, a disclosure triangle appears to the left
of the name, and you can open the array.
At the same time, the New Sibling button changes to New
Child. You create one new child to begin with. Once you have
done so, you select it and use the New Sibling button to create
other second-level values. In practice, this turns out to be very
simple, and it is logical, but you may need to get used to the
interface.
The first entry in the NSServices array is numbered 0 ~ y o u do
not change the number. You can add additional services, but
it is usually easiest to start with one to make certain that it
works properly.
Go through the process again: Select the 0 entry, change its
type to a dictionary with the pop-up menu, and then use the
New Child button to create a subentry. Selecting that suben-
try, you can use the New Sibling button to add more as shown
in Figure 27-3.
To rename any entry, just double-click on its default name
and change the name. All of the property names (at the left in
the figures shown here) are required. The ones at the right are
not. Here is what the various properties mean:
This is the text that will appear in the Services
menu for all applications. It is grayed out if your service is not
applicable (based on the current selection and the items that
the current object can receive by way of pasted values).
This is the name of the method in the services
provider object of your application that will be called. (You
will create this method in the next section.) It is not the name
of an existing method in your application before you have
added services. It may call an existing method, but it is a new
one just created to handle services.
This is your application's name.
This is an array of one or more types that
your service will return. It can include standard Cocoa paste-
board types, or it can hold types specific to your application--
or a mixture. For input-only services, the array is empty.
NSSendTypes This is the companion array of types that can
be sent to your service. For output-only services, it is empty.
N S U s e r D a t a This is a string that is passed into your service
provider's method. You can use it for dispatching code so that
one method provides several services. You could also use it to
identify the requester of the service. This could be part of a se-
curity implementation. Remember, though, that the string is
c o n s t a n t ~ i t is specified in the property list, so you cannot
modify it w h e n the service is requested. NSUserData is op-
tional.
Services are managed by a service provider object. You create
this object (as a descendat of Object in Java or NSObject in Ob-
jective-C), and you implement methods in it to handle each of
the service requests. (If you use the optional NSUserData
property, a single method can handle multiple service re-
quests with the dispatching controlled by the NSUserData
string that is passed in from the property list.) At run time,
you instantiate this object and set it as the application's ser-
vice provider.
Creating the Service Provider Create a new class in your ap-
plication: Go to the New File command in the File menu and
choose Java Class or Objective-C class.
In Diary, an input-only service is provided. If you select some
text in an application, you can choose N e w Diary Entry from
the Services menu: A new Diary entry will be created with
that text as the main text, with a title that consists of the date
and time, and with a subtitle reading "Created by a Mac OS
XService." (The user presumably will change these.) This is a
simple way to quickly add a Diary entry from any text that
you find in an email, a document you read, or a Web site.
The service provider class can have any structure that you
want. In this case, it needs to be instantiated with a reference
to the DiaryDocument object itself so that the service can use
the reference to create a new entry. Here is the shell of the ser-
vice provider code:
Java:
Objective-C:
You create an instance of this class and then install it as a ser-
vice as soon as your application starts up. In the Diary appli-
cation, the service class is called DiaryService. Here is the
instantiation and installation code. Because it needs the refer-
ence to DiaryDocument, it is located at the end of the con-
structor for DiaryDocument in Diary.
Java"
Objective-C"
You will note that the constructor and initializer of this object
take a reference to r s / s e 1 f. At this point, that is the doc-
ument object. This reference allows the service to access the
document data that it will need).
Next, you write the code
for your service provider. You can do whatever you want
within it, but you must implement each method you have
identified in the NSMessage property item for each of your
services. Each of these methods has three arguments:
0 A pasteboard from which you can take data and to
which you m a y return data.
0 A string which is the string (if any) you specified in the
NSUserData property.
0 A string containing an error message that you can re-
turn.
In the method, you need to retrieve
the text from the service request; you the create a Diary entry.
The procedure for retrieving the text is common to many ser-
vices. In fact, the underlined code in these snippets is the boil-
erplate code you use to retrieve any data from the clipboard
(pasteboard). The calls to create the Diary entry are not boiler-
plate, but they are analogous to the calls you make to imple-
ment your own services. Note that this code contains no error
checking, and the literal string used w o u l d normally be de-
clared as a constant.
Java:
Objective-C:
Services provide a long-wanted facility to share applications'
functionality. You can incorporate them into your applica-
tions and workflows as well as provide them to others. They
are an important new feature of Mac OS X that helps you to
create your own custom solutions.Also available in Mac OS X
is AppleScript: the user programming language that your ap-
plication can support. It is the topic of the next chapter.
AppleScript has been one of the most popular features of the Mac OS
since its debut in System 7. On Mac OS X, it is available in the Car-
bon and Cocoaframeworks. The implementation on Cocoa is differ-
ent from that on Carbon in a number of significant ways that reflect
the Cocoa architecture.
Mac OS X provides users with a vast array of ways to do things, and
that includes going about the tasks of running programs and doing
the work (and play) that they want to do. Continuing Apple's tradi-
tion of user-centric computing, users now have the ability to do the
same thing with the keyboard and mouse, from the command line,
from scripts~and with the integration of services. The developer's
job is to create the functionality and package it in as many of these
formats as possible so that the user can find it and take advantage of
it in the easiest way possible.
Because of its importance, AppleScript is documented well on Ap-
ple's developer Web site. There are many constants defined for use
in the grammar files. This chapter walks you through a very simple
grammar to show you how to get started.
The intensely interactive point-and-click/typing interface
was a welcome breath of fresh air to computer users who
were tired of typing obscure commands into their computers.
For certain tasks (among them, content creation~that is, writ-
ing, drawing, and multimedia editing), this interactivity can-
not be beat.
Yet for other tasks~intensely repetitive and boring tasks such
as reformatting scores of images from TIFF files to JPEG
files~the interactivity is a pain. It does not matter that the
command line was gibberish: Typing in one line of gibberish
and then going home for the night while the computer works
may be worth it.
Early automation tools for the interactive interface focused on
simulating mouse and keyboard processing. These scripts
and macros worked well once they were developed, but they
were prone to problems caused by any change in the environ-
ment. If a dialog box moved a fraction of a hair on the screen,
the preprogrammed mouse click went awry.
It is in this context that Apple started to develop Apple events
and AppleScript: projects that would make an application's
objects and functionality programmable by users. Apple-
Script is a language with syntax that is not hard for advanced
users to master. Furthermore, it was designed from the start
to be used with a variety of d i a l e c t s ~ p r o and novice as well
as French and Chinese.
There are two parts to AppleScript: classes and commands.
You m a y implement either of them, but normally both are im-
plemented in one w a y or another. You define classes to repre-
sent your application's data objects. Internally, you can write
a variety of functions to support the translation from Apple-
Script to object: People are used to writing about the fifth ob-
ject, the first, or the last, and you must support that. (With
interactive applications, you do not w o r r y about this issue be-
cause the user clicks on whichever object is to be acted on.)
The commands that you define represent your application's
functionality. They m a y also represent its interface. Apple-
Script in Cocoa is supported at both the AppKit and Founda-
tion levels. In architectural terms, it is implemented in your
model (data) classes as well as in your view (interface) classes.
The reason for this is that users do not make the distinctions
that developers make. Some scripts are designed to automate
tasks that appear logical and integrated to a user but not to a
developer.
Take as an example a real-life set of instructions to a personal
assistant. These might include opening the mail and prepar-
ing a cup of morning coffee--clearly substantive tasks. The in-
structions might also include an instruction to tilt the w i n d o w
blinds in a certain w a y - - s u r e l y an interface type of task. Yet,
to the user, all are of equal importance: When they are com-
pleted, work can begin.
Scripting is used in a variety of ways to make users' and de-
velopers' lives easier.
You can use scripting yourself to
run your application through its paces in order to test it. The
advantage of automated test suites of any sort is that you can
accumulate all sorts of interesting combinations and run
through them overnight or during a weekend. The repeatabil-
ity of an automated test suite makes it an ideal tool for quality
assurance.
AppleScript is used to drive demonstra-
tions. You can build scripts that run your application over and
over, but you can also build them to stop at given points.
Solutions and Integration AppleScript is used extensively in
solutions that involve integration of several products (a data-
base, for example, and a page layout program). AppleScript
consultants write solutions from your building b l o c k s ~ i f
they are scriptable. If they are not, they may go elsewhere. The
users of AppleScript are a very vocal group in the Macintosh
community!
You can write scripts that run to a certain point and
then stop, allowing the user to continue if possible.
You can also write scripts that revert an environment
back to a k n o w n condition. These are popular in computer
labs as well as in training environments where the script has
run to a certain point, and then stopped to allow the user to
c o n t i n u e ~ b u t the user doesn't have a clue and just walks
away leaving the computer in a befuddled mess. A setup
script can restore everything to a k n o w n state.
If your application is scriptable, it recognizes AppleScript
commands that users write. In addition, users can open its dic-
tionary from the Script Editor Open Dictionary command in
its File menu to find out what scripting commands they can
use.
The dictionary, shown in Figure 28-1, reflects your Apple-
Script syntax. It is formatted by Script Editor from your script-
ing resources. Because it is formatted from these resources, it
always matches the syntax. Also, because no additional cod-
ing on your part is required, the dictionary is always avail-
able.
To display your application's dictionary and to make it script-
able, you must add N S A p p l e S c r i p t E n a b l e d to your prop-
erty list in Project Builder. In the Targets pane, select your
project. Then, click the Application Settings tab, followed by
the Expert button as shown in Figure 28-2.
Next, you build your grammar.
You build your grammar in two parts: The script suite is the
programmer's view of your AppleScript support, and the ter-
minology file is the localized version. You have one script
suite file and as many terminology files as languages that you
support.
The script suite file should be placed at the top level of your
Resources folder in your project and on disk. The terminology
files should be placed in the appropriate lproj folders on disk
(English.lproj, Dutch.lproj, or whatever). They will automati-
cally appear in the Project Builder hierarchy organized to-
gether.
Figure 28-3 shows the Project Builder hierarchy; Figure 28-4
shows the Finder hierarchy. (Remember to use the Add File
command from the Project menu to add the files to your
project after you have placed them properly on disk.
The script suite and terminology files have a similar structure.
Stripped of all the actual code, here is what the s c r i p t s u i t e -
f i 1 e looks like:
These files quickly get quite lengthy, so it helps to know your
way around them. Note that if you do not have classes or
commands, those sections do not appear at all.
To implement support for classes, you need to write code in
the script suite, the terminology file, and your application.
The Classes section of Dia-
ry.scriptSuite is shown here. You can see its logical structure
represented in the dictionary shown in Figure 28-1.
Note that for each class your application responds to, you
must provide its superclass as well as an event code. You may
also provide details of its internal structure using ToManyRe-
This code defines three classes: NSApplication, DiaryEntry,
and DiaryDocument. Within the NSApplication class, one
key is defined: o r d e r e d D o c u m e n t s . Within DiaryDocu-
ment, another key is defined: e n t r i es. These will be used in
your application code.
maps your AppleScript terminology to an individual lan-
guage. Here is the terminology file for the script suite:
"Classes" = {
The file is fairly self-explanatory. For each class defined in the
script suite, natural language names and a description are
provided. These are what show up in the Script Editor dictio-
nary.
Application Support You can implement a number of meth-
ods that help AppleScript run through objects to find the third
word of the fifth paragraph and so forth. At a minimum, you
should implement accessors for the keys that you defined in
the script suite. These have the standard naming convention:
s e t K e y and key for setters and getters, respectively.
Handling commands is similar to classes. You define them in
the script suite file, set their terminology, and then implement
them in your application.
This chapter harks back to the question posed in this book's
introduction: "Who is a programmer?" By making your appli-
cation scriptable, you provide the raw material for the end
user as programmer. That person, in turn, can take your work
and combine it with other work products to create something
new and undreamed-of.
The last chapter of this book pursues this paradigm one more
step as it explores the possibilities for writing reusable code
for programmers.
This Page Intentionally Left Blank
If you refer back to the diagrams in Chapter 2 that describe the evo-
lution of Mac OS X, you will see that the operating system and its
application programs have grown from a monolithic blob of code
custom-written for every task to a sophisticated collection of inter-
acting components, most of which are used and reused. Users, too,
are coming to understand and appreciate this architecture. Instead
of the mysterious blob of "the system" and its extensions, control
panels, plug-ins, and the like, today's Mac OS X users can see that
their computers run dozens of programs at a time.
The benefits of componentized software are well known; the problem
has always been implementing components in the real world. With
Mac OS X, users can see the individual components at work (using
Process Viewer), and they can use them and assemble them into cus-
tomized solutions using the command line in Terminal, Apple-
Script, and Services.
You automatically reap the benefits of componentized software when
you use an object-oriented framework such as Cocoa, MacApp, or
PowerPlant. But there is yet another type of component reuse avail-
able to you through the use of reusable code that you assemble.
This chapter provides an overview of the two main strategies for re-
using code across applications: frameworks and palettes. As with so
much of the Mac OS X architecture, it just works. In addition, it is
a very powerful architecture. So you might as well use it.
Frameworks on Mac OS X are dynamic linked libraries that
are packaged in a versioned bundle. Note that this usage of
"framework" is different from its usage in the sense of an ob-
ject-oriented framework such as Cocoa, MacApp, or Power-
Plant. Frameworks as dynamic linked libraries in Mac OS X
need not be object-oriented, although they frequently are.
A framework encapsulates code that can stand more or less by
itself. At one extreme, it can be common code that is used by
many applications. At another extreme, it can be very esoteric
code that is used by few a p p l i c a t i o n s ~ b u t you may not want
its source code modified or even viewed by the programmers
who use it.
A framework also can be an effective w a y of combining pro-
gramming languages. Using the Java bridge, you can expose
Objective-C objects to Java programmers, and vice versa.
Finally, frameworks can be a very good way of splitting a pro-
gramming project into independent components that sepa-
rate programmers or teams of programmers can work on.
Once you have created a framework in Project Builder, you go
about programming it just as you would any other code: You
declare objects, variables, and methods, and write normally.
You can add files to the framework just as you always do.
Frameworks cannot run on their own. As a result, if you are
building a framework, you normally build a companion
project to incorporate it and run it so that you can test it.
How Frameworks are dynamically linked shared libraries. This
means that when a program runs, it is linked to a single copy
of the library to which other programs may also be linked.
Only one copy of the library code runs. This can improve effi-
ciency (each of the application programs is smaller, because
the shared code is in the single library).
Dynamic linking happens at the last possi-
ble moment. (The alternative is static linking, which happens
at the end of the compilation process.) Only those parts of the
framework that are needed are linked.
Because symbol resolution (the process of linking) is done on
an as-needed basis and at the lowest possible level, you
should be careful that you plan for it. Related methods and
objects should be in the same module if they will be used to-
gether; the module will be linked and all will be available. On
the other hand, if some related code is used frequently and
other equally related code is used infrequently, you may want
to attempt to separate them so that the less frequently used
code is not linked unnecessarily.
Frameworks may contain multiple versions of themselves.
Mac OS X takes care of linking to the appropriate one, provid-
ing that you have set the version properly (see "Versioning
the Framework" on page 576).
Because a single library may be shared by many
programs at the same time, the code must be reentrant. That
is, any process that is linked to it must be able to use it without
coming into conflict with another process. This applies at the
low level of code as well as at the higher level of architecture:
If the library stores any information in a common variable (or
on disk), that information must not be specific to a client un-
less it is so identified.
When you deploy frameworks,
they are normally placed in the Frameworks folder within a
Library folder. Library folders exist in a user's home directo-
ry, at the system level, and at the network domain. When a
dynamic linked library needs to be loaded, Mac OS X looks in
these places (in that order).
You create frameworks in Project Builder by using the N e w
Project c o m m a n d from the File menu. Choose the appropriate
item from the list. Project Builder will automatically set up the
files and build settings for you.
Inside the framework, you write code that you will want to
use from other applications. In those applications, you use a
framework by choosing A d d Framework (not A d d File) from
the Project menu. Project Builder will import it properly.
Use the Target button in the project structure pane of Project
Builder to go to Build Settings. Set to
the current version of your framework. By default, this vari-
able starts with A.
Palettes often are used with frameworks. They are compo-
nents that can be added to Interface Builder so that your new
interface elements can be used and reused.
The same reasons for using frameworks apply to palettes:
They encapsulate functionality that you do not want to have
to reimplement each time you use it.
You create a new palette in Interface Builder by choosing IB
Palette from the list of choices in the Starting Point. Your pal-
ette can be a combination of existing Interface Builder objects
(in a customized window, for example, that you will want to
use in many applications for your organization). More often,
however, it involves custom objects (including custom views)
that you want to reuse.
If you have custom objects in your palette, you match the pal-
ette up with a framework that provides the code for the ob-
jects. You need to write three sets of code for your palette
objects:
0 You write the functional code that you would always
write to support an object~outlets and actions.
0 You override IBPalette to implement the object's func-
tionality within Interface Builder (such as the setting
of connections using the Info window).
0 You override IBInspector to provide other informa-
tion.
If you are building a framework to support a palette, you in-
clude InterfaceBuilder.framework.
This is the object that is instantiated at run time in the final ap-
plication. The palette objects are normally subclasses of NS-
View (or of other view objects). You implement the same basic
functionality that you would write in Project Builder if you
were coding the object directly.
You must make certain to override coding methods so that the
object can be read and written. If it contains any data (such as
values the user may have set in Interface Builder), this step is
required. If it uses only default values, you do not have to do
this.
Here are the shells of the methods you implement:
This is the object that you manipulate in Interface Builder as
you build your interface. Create a descendant of IBPalette for
your palette object. Depending on the object, you may need to
allocate (and deallocate) variables as it is created. You may
You override IBInspector to implement the functionality your
object displays in the Info window (formerly called the In-
spector window--hence the name).
You also may provide a nib with interface elements that will
appear in the Info window's Attributes pane to let users set
your object's values. If so, you must load this nib in your IB-
Inspector i n i r method.
You always override the methods that complete actions in the
Info w i n d o w - - o k and r e v e r t . If your object has data values
(titles or labels, for example), you move them from the view
into the variables that will be stored.
Perhaps the most important thought for developers to take
away from the world of Mac OS X is that programming in that
environment starts from a much more sophisticated level
than in most other environments. Core Foundation and Co-
coa's Foundation framework wrap simple concepts in power-
ful classes and class wrappers; Apple Class Suites bring such
classes to C++ along with sophisticated error checking.
The Carbon and Cocoa frameworks handle interface and
event dispatching quickly and with very little need for cus-
tom-written code. What code you do write can be provided to
users and other developers for further use with AppleScript
and through frameworks and palettes you create.
In short, from a developer's point of view, Mac OS X is a font
of productivity tools that you can use and create for others to
use. It also is a sophisticated and elegant user experience with
its Aqua interface, and the frameworks help you take advan-
tage of and adhere to the interface guidelines.
Mac OS X is missing one important feature: your imagination.
Whether it is sophisticated business logic, imaginative media
authoring tools, or as-yet-unheard-of ideas, Apple has done
its part. The rest is up to you.
sending 403
== 180 actions (Cocoa) 111, 116
68K calls 144 addObserver 411
addPage (TextEdit) 427
advertising 295
AE (Apple event scripting framework) 152
Algol 6
alloc 391, 501
A AppKit 116-123
accessors 146, 371 classes
for Carbon events 159 color 121
ACS. See Apple Class Suites documents 121
action events 396 fonts 120
actions 273 graphics 120
interface 118 breakpoints (in Project Builder) 218
Interface Builder support 123 browsers 469
international support 123 build phase 314
operating system support 122 build phases (in Project Builder) 231
printing 122 build settings (in Project Builder) 232
Apple Class Suites 181-182 build styles (in Project Builder) 236
Apple Help 203, 301 bundle 312, 314-317
Apple Installer 313, 321-322 bundle services (Core Foundation) 180
AppleScript 138, 195, 306, 561-571 buttons
application support 569-571 bevel 460
grammars 566-568 push 459
terminology file 568 radio 464
application round 460
bundle 314-317 square 460
event class (Carbon) 158
packaging 311-324
settings (in Project Builder) 232
structure
Carbon 360
Classic 360
C
applicationDockMenu 521 C with Classes 96
applications C++ 81, 95, 201
AppleScript delegation 103
implementing 569-571 fragile base class problem 85, 100
immersive 545-546 multiple inheritance 101-102
scriptability 565 static typing 97
Aqua 144 vtables 100
Aqua interface 202-203 Carbon 141-173, 201
shadow (of views) 419 application structure 360
archiving 134, 475--478, 504 applications
archiving classes (Foundation) 138 creating in Project Builder 229
ATS (Apple Type Services framework) 152 event classes. See event classes (Carbon).
autorelease pools 133 events 154-172
awakeFromNib 251 accessors 159
frameworks 147-154
Interface Builder 278-280
nibs 247
CarbonCore 153
CarbonLib 147
B category (Objective-C) 88
base services (Core Foundation) 179 CFEqual 180
BeginFullScreen 545 CFHash 180
beta testing 290 CFPreferencesCopyAppValue 390
bevel buttons 460 CFPreferencesSetAppValue 389
bit-mapped graphics 121 CFRelease 179
bookmarks (in Project Builder) 217 CFRetain 179
CFURLCreateDataAndPropertiesFromRe- coordinate system 439
source 181 Core Foundation 176-181
change management 510-515 base services 179
changers 512 bundle services 180
checkboxes 464 collection services 180
checking files in (CVS) 335 creating and copying objects 178
checking out (CVS) 330 plug-in services 180
Classic preference services 180
application structure 360 property list services 181
Classic environment 202 string services 181
clipboard 122, 532 URL services 181
coalescing (of notifications) 408 utility services 181
Cobol 6 XML services 181
Cocoa 109, 201 CoreGraphics 152
AppKit. See AppKit createDiaryDictionary 505-506
applications creating and copying Core Foundation
creating in Project Builder 228 objects 178
nibs 247 CVS 211,325-340
main file 248 checking files in 335
programming design checking out projects 330
terminology 110-116 committing changes (CVS) 335
Code Fragment Manager (CFM) 143 comparing files 333
CodeWarrior 143, 207, 239-242 creating a repository 328
coding 475 importing projects and files 329
collection services (Core Foundation) 180 preferences 338
collections 376-383 remote servers 339
collections classes (Foundation) 137 repository 328
color classes (AppKit) 121 reverting 337
color well 463 setting up 327-330
ColorSync 152 version info 333
combo boxes 465 CVSROOT 328
command event class (Carbon) 158
command line 204
Project Builder 238-239
commandID 164
commiting changes 335
CommonPanels 150
D
connections 110, 115, 275, 491 Darwin 144
creating in Interface Builder 256, 259 data
constructors 391 factoring 369
content view 419 fishing through objects 371
context (of events) 162 restoring 507-510
contextual menus 299, 519-520 saving 503-506
control event class (Carbon) 158 data browser 204
control panels 145 data display 467-470
controls. See under user experience progress bars 467
text 467 undo 510-515
data entry 461-466 See also NSDocument
images 463 doesNotRecognizeSelector 135
text 461-462 domains
data hiding. See encapsulation for preferences 386
data modeling 368-375 drag-and-drop installation 313
data strategy 368-375 drawers 204, 451
dataRepresentationOfType 504-506 toggleDrawer 451
delegate drawing 423
for NSWindow 434 drawRect 424
delegates 114, 403--404 Dylan 80-81
and notification 409-415 dynamic binding 110
window 434 dynamic linking 11,575
delegation 356 in Objective-C 85
in C++ 103 dynamic typing 110
in Mac OS X 104 in Objective-C 82
Diary 344-352 dynamism 63, 110
classes 352-355 in Objective-C 82
DiaryData 354
DiaryDocument 352
diaryDocumentData 384, 505
DiaryEntry 354
dictionaries
AppleScript 564
E
dictionary. See NSDictionary encapsulation 57
direct dispatch (in Carbon) encodeWithCoder 578
setting up 162 EndFullScreen 546
direct-dispatch (Carbon) 157-172 EPS (Encapsulated PostScript) 120
dirtying documents 510-515 event
disclosure triangle 455 formats 397
disk drivers 144 handler (Carbon)
disk images 317-320 installing 168
distributed objects 492 programming 165
distributed objects classes (Foundation) 138 kinds (Carbon) 158
distribution 483 loop (Carbon) 154
Dock menus 520-522 running 172
dockMenu outlet 521 event classes (Carbon)
documentation 294 application 158
documents 495-515 commands 158
and views 498 controls 158
classes (AppKit) 121 keyboard 158
dirtying 510-515 menu 159
implementing in Cocoa 499 mouse 159
print info 531-532 tablet 159
restoring data 507-510 text input 159
saving data 503-506 window 159
events 396-398
action 396 G
Carbon
identifying event targets 162 games 537--547
identifying (for direct dispatch) 158 GDB debugger 210
Cocoa 111 GetEventClass 160
timers 398 GetEventKind 160
views 427 GetEventParameter 160
EventTargetRef 168 GetEventRetainCount 160
EventTypeSpec 165 GetEventTime 160
exception handling 27 GNU compiler 210
Java 73 graphics classes (AppKit) 120
extensions 145 guidelines (in Interface Builder) 269
F H
failures, testing of 289 hardware access (direct access from code) 144
File's Owner 251 help 150
files 495-515 AppleScript 306
FindByContent 153 automated searching 306
first responder 252, 277, 400-401 buttons 297
fonts classes (AppKit) 120 canned search 306
Fortran 6 cuteness (recommendation against) 297
forwardInvocation 90~ 139 developing 293-309
Foundation documentation 294
archiving 138 help tags 297
classes indexing 302
values 136 launching
collections 137 AppleScript 306
distributed objects 138 application 306
framework (Cocoa) 123-140 naming of interface elements 296
notifications 138 onscreen information 295
Objective-C language services 138 recognizing experience 297
operating system services 138 searching 302
scripting 138 task-oriented focus 296
strings 136 tool tips 297
fragile base class (in C++) 85 help book 302
fragile base class problem 100 help buttons 297
frame 419 Help Center 305
frameworks 49-64 Help menu 301
Java 73 help tags 203~ 297
writing 574-576 Interface Builder 298
full screen 545-546 Help Viewer 301-308
HID manager 538-543 radio 464
HideWindow 546 round 460
high-level language 6 square 460
HIToolbox 150 checkboxes 464
hooks color well 463
window display 437 combo boxes 465
Hopper, Grace 7 image view 463
HTMLRendering 150 placards 466
Human Interface Device Manager. See HID pop-up menus 464
manager progress bars 467
radio buttons 464
sliders 466
small 470
' ,,
steppers 460
tab views 468
I table views 470
IBCarbonRuntime 151 text fields 461
IBInspector 579 text views 462
IBPalette 578 views
image view 463 outline 470
ImageCapture 151 table 470
images factoring 369
NSImage 440 information 467--470
NSImageRep 440 organizing controls 468-470
views 265 user actions 457-460
immersive applications 545-546 user input 461-466
info.plist 553-556 Interface Builder 245-281
inheritance 56 actions 273
init 501 Carbon 278-280
init methods 391 connecting outlets 369
initWithCoder 578 connections 256, 259, 275
initWithCondition 490 designing with 269-271
input 461--466 guidelines 269
installation help tags 298
disk images 317-320 measurements 269
drag and drop 313 menus 253
packages 313 outlets 274
testing 323 palettes
installer packages 321-322 custom 576-579
interface 453-471 programming for 271-278
controls 457-470 sizing views 420
boxes 468 tool tips 298
browsers 469 views 262
buttons windows 258
bevel 460 Interface Builder support classes (AppKit)
push 459 123
interface classes (AppKit) 118 layoutRect 420
interface errors, testing of 289 Lisp 80-81
international support classes (AppKit) 123 loadDataRepresentation 507-508
IOCreatePlugInInterfaceForService 541 loadDiaryToDictionary 504
IOKitLib.h 540 loadFieldsFromDiaryData 409
IOObjectGetClass 541 loadPropertyListRepresentation 477--483
IOServiceGetMatchingServices 540 locking 488-491
J M
Java 65-77, 201 Mac OS X
applications evolution of 37-47
creating in Project Builder 229 MacApp 112, 183-188, 201
constructors 391 TApplication 360
exception handling 73 Mach 34-37, 486
frameworks 73 Mach ports
Object class 68 creating 539
packages 72 freeing 543
Java bridge 74-77 Mach-O 143
java.lang.reflect 402 main window 113
JavaBrowser 74 makeFirstResponder 400, 438
JBuilder 207 makeKeyAndOrderFront 438
joysticks 538 makeScalePopUpButton (TextEdit) 429
measurements (in Interface Builder) 269
memory management 27, 35, 179
menu bar
hiding 545-546
menu event class (Carbon) 159
K menus 517-523
key window 113 contextual 519-520
keyboard event class (Carbon) 158 creating in Interface Builder 253
keyboards 538 Dock 520-522
knobs 538 pop-up 464
messaging 27, 36
methodSignatureForSelector 139
Metrowerks 207
modem OS
L exception and fault handling 27
memory management 27
LangAnalysis 153
messaging 27
Latitude 108
process management 27
LaunchServices 153
security 27
layout guidelines 203
mouse event class (Carbon) 159
MPW 143 NSCopying 484
multiple inheritance 101-102 NSData 136
multiprocessing 146 archiving 476
NSDictionary 137, 179-180, 377-382
archiving 476
IOServiceGetMatchingServices 540
key/value pairs 379
saving and restoring documents with
N 503-510
NavigationServices 151 NSDocument 122, 495-515
Network Services Location. See NSL constructors 501
NewEventHandlerUPP 169 opening nib files 249
nib files responder chain 399
opened by NSDocument objects 249 subclassing 499
nibs 247, 436 NSDocumentController 122
Dock menus 521 NSDrawer 451
for documents 502 NSEvent 118, 397
notifications 359, 404-409 NSException 138
addObserver 411 NSFileWrapper 122
and delegates 409--415 NSFont 120
coalescing 408 NSFontManager 120
postNotification 414 NSFormatter 136
registering for 410 NSImage 120, 440
window 434 delegate 440
notifications classes (Foundation) 138 NSImageRep 120
NSAppleScriptEnabled 565 registry of image types 440
NSApplication 355-359 NSInvocation 133
delegates NSL (Network Services Location) 151
applicationDockMenu 521 NSLCore 153
delegation 356 NSLock 489
notifications 359 NSLocking (protocol) 490
outlets NSMenuItem 555
dockMenu 521 NSMessage 555
NSArchiver 476 NSMovie 121, 543-545
NSArray 137, 377 NSMovieView 543-545
NSAssertionHandler 138 NSMutableArray 382
NSAttributedString 137 NSMutableCopying 484
NSAutoreleasePool 138 NSMutableDictionary 382
NSBezierPath 426 NSMutableSet 382
NSCell 119, 119 NSNotification 406--408
NSCoder 134 NSNotificationCenter 408--409
NSColor 121 NSNotificationQueue 408
NSColorPicker 121 NSObject 124-136
NSConditionLock 489 archiving 134
NSConnection 491 doesNotRecognizeSelector 135
NSControl 119 dynamism 136
error handling 135 Objective-C 79, 201
fabrication 127 alloc 391
forwardInvocation 90 category 88
functionalities 126 class and instance objects 86
identification 131 classic syntax 91
introspection 130 dynamic linking 85
memory management 133 dynamic typing 82
message handling 131 dynamism 82
respondsToSelector 90, 112, 132 init methods 391
serialization 134 protocols 88
NSPasteBoard 122 Objective-C language services classes (Foun-
NSPortName 556 dation) 138
NSPrintOperation 526 object-oriented programming 49-64
NSProxy 124, 138 benefits 52
forwardInvocation 139 design issues 56--62
methodSignatureForSelector 139 encapsulation 57
NSRecursiveLock 490 inheritance 56
NSResponder 112, 119, 398 learning curve 53
NSReturnTypes 556 memory management 63
NSSendTypes 556 messages vs. methods 80
NSServices 555 performance 62
NSSet 137, 382 polymorphism 56
NSString 179 run-time issues 62--64
NSText 120 terminology 54
NSTextField 461 objects
NSTextView 120 creating 390-393
NSThread 491 creating from serialized data 478
NSTimer 398 objects (Cocoa) 110
NSUndoManager 138 onscreen information 295
NSUserData 556 opaque data structures 146
NSUserDefaults 388 opaque types (Core Foundation) 177
NSValue 136 OpenGL 121
NSView. See views OpenScripting 151
NSViewMaxXMargin 422 operating system services classes (Founda-
NSViewMinXMargin 421 tion) 138
NSViewWidthSizable 422 operating system support classes (AppKit)
NSWindow. See windows 122
NSWindowController 436 OSServices 153
NSWorkSpace 123 OT (Open Transport Carbon framework) 153
outlets 110, 115, 274
connecting 369
outline views 470
output 467-470
Object class (Java) 68
Expert 553-556
P application settings 232
bookmarks 217
packages (Java) 72 breakpoints 218
packaging 311-324 build phases 231
palettes build settings 232
creating 576-579 build styles 236
pasteboard. See clipboard building projects 231-238
pbxbuild 211 Carbon applications (creating) 229
PDF 121,294, 532 Cocoa applications (creating) 228
periodic events 111 command line 238-239
PICT 121 creating a new project in 228
placards 466 creating files in 230
planning 193-205 CVS 331-335
plug-in services (Core Foundation) 180 frameworks
polymorphism 56 creating 576
pop-up buttons. See pop-up menus info.plist 553-556
pop-up menus 464 Java applications (creating) 229
ports 491 palettes
creating 539 creating 576-579
Mach Project Structure Pane 213
freeing 543 source code management 331-335
postNotification 414 targets 213, 217, 237
PowerPlant 112, 201 toolbar 227
preemptive multitasking 144 project planning 193-205
preference services (Core Foundation) 180 proofs of concept 196
preferences 386-390 property list services (Core Foundation) 181
CFPreferencesCopyAppValue 390 property lists 384-386
CFPreferencesSetAppValue 389 propertyListRepresentation 476-483
domains 386 protected memory 144
NSUserDefaults 388 protocols 72, 88, 102
Preferred Executable Format (PEF) 143 prototypes 196
prepareWithInvocationTarget 513 prototyping 283-291
Print (Carbon Printing Manager) 151 public testing 290
print info 531-532 push buttons 459
print panels 530-531
PrintCore 153
printing 144, 525-536
printing classes (AppKit) 122
printOperationWithView 526
printShowingPrintPanel 527-528 Q
process management 27 quality icons 203
progress bars 467 QuickDraw 153
Project Builder 143, 207-243 QuickTime 543-545
application bundle (creating) 314
Application Settings
application name 556
business models for 552
input-only 551
radio buttons 464 menu command name 555
reference counts 179 method name 555
reflection (Java) 402 NSUserData 556
registerUndoWithTargetAndArguments 513 output-only 551
regression testing 290 return types 556
release 133 send types 556
repository (CVS) 326 service provider 556-560
resource forks 248 setNeedsDisplay 424
responder chain 113 setServicesProvider 558
NSDocument 399 sheets 204
vs. target chain 114 sliders 466
responders 112, 398-403 Smalltalk 80-81
views 427 SOM 86
respondsToSelector 90, 112, 132, 401 sort button 455
restoring source code management. See CVS
data 507-510 SpeechRecognition 152
print info 531-532 SpeechSynthesis 153
retain 133 static typing 97
reverting (CVS) 337 steering wheels 538
RTF (Rich Text Format) 120 steppers 460
string services (Core Foundation) 181
strings classes (Foundation) 136
Stroustrup, Bjarne 101
switches 538
S synchronism 485-492
saving connections 491
data 503-506 kinds of 485
print info 531-532 locking 488-491
screen buffer 144, 545 NSConditionLock 489
Script Editor 564 NSLock 489
script suite 566 NSLocking (protocol) 490
scriptability 198, 565 NSRecursiveLock 490
scripting classes (Foundation) 138 NSConnection 491
security 27 NSTask 491
SecurityCore 154 NSThread 491
SecurityHI 152 opportunities for 487
SEL 401 tasks 488, 491
selectors 401-402 threading 487, 491
Java 402 system appearance 203
Objective-C 401 system testing 289
serialization 134, 478, 504 System/360 25
services 110, 205, 549-560
creating 445
T trackballs 538
trap patching 145
tab views 267, 468 trap tables 145
table views 470 triangle (mysterious little) 455
tablet event class (Carbon) 159
tabulation views 267
TApplication 360
target chain
vs. responder chain 114
targets (in Project Builder) 213, 217, 237 U
tasks 488, 491 unarchiveObjectWithData 477
terminology 568 unarchiving 477
test suites 290 undo 510-515
testing 283-291 undo stack 514
beta testing 290 undoManager 514
by users 291 Unicode 66, 181
failures 289 unit testing 289
installations 323 UNIX 24
interface errors 289 unloadFromDictionary 504, 509
primary functionality 289 unlockWithCondition 490
public testing 290 URL services (Core Foundation) 181
regression testing 290 URLAccess 152
system testing 289 USB devices 538-543
test suites 290 closing 542
unit testing 289 communicating with 542
text entry 461 creating interfaces to 540
text fields 265, 461 finding 540
text input event class (Carbon) 159 identifying 543
text views 265, 462 opening 541
TextEdit user experience 202-204, 453-471
addPage 427 Apple Help 203
makeScalePopUpButton 429 Aqua interface 203
thread safety 179 controls 457-470
threading 179, 491 boxes 468
threads 487 browsers 469
thread-safe code 146 buttons
throttles 538 bevel 460
toll-free bridging 179 push 459
tool tips 297 radio 464
Interface Builder 298 round 460
toolbar (in Project Builder) 227 square 460
toolbarAllowedItemIdentifiers 444 checkboxes 464
toolbarDefaultItemIdentifiers 443 color well 463
toolbarItemForItemIdentifier 447 combo boxes 465
toolbars 440-450 image view 463
outline 470 drawing 423
placards 466 drawRect 424
pop-up menus 464 events 427
progress bars 467 frame 419
radio buttons 464 geometry 419
sliders 466 hierarchies 418
small 470 identifying 427
steppers 460 image views 265
tab views 468 layoutRect 420
table views 470 outline 470
text fields 461 printing 526
text views 462 removing 433
views resizing behavior 421
outline 470 responders 427
table 470 setNeedsDisplay 424
data browser 204 shadow (Aqua) 419
drawers 204 tab views 267~ 468
help tags 203 table 470
immersive applications 545-546 tabulation views 267
information 467-470 text fields 265
layout guidelines 203 text views 265
organizing controls 468-470 See also under interface
quality icons 203 virtual memory 144
sheets 204 visualization 417-452
system appearance 203 vtables 100
testing of 289
user actions 457-460
user input 461-466
window layering 203
See also help
user testing 291
W
users 198 WaitNextEvent 154, 172
utility services (Core Foundation) 181 widgets 455
window controllers 503
window event class (Carbon) 159
window layering 203
Window Server 434
windowControllerDidLoadNib 249
windows 417-452
values 136 controllers 435
values classes (Foundation) 136 creating in Interface Builder 258
views 417-452 delegate methods 434
adding 427-433 makeFirstResponder 438
and documents 498 makeKeyAndOrderFront 438
browsers 469 printing 526
creating in Interface Builder 262 setting position 438
setting responder 438
See also under interface
writing tablets 538
X
XML 384
XML services (Core Foundation) 181
This Page Intentionally Left Blank
JESSE FELLERis the author of a number of Mac OS X books including Mac OS X: The
Complete Reference and Java Programming on Mac OS X. He is also the author of
WebObjects 5 Developer's Guide, as well as many books on the Web-based enter-
prise (such as Database-Driven Web Sites and Managing the Web-Based Enterprise),
the Y2K problem, home offices, databases, and FileMaker. His books on Open-
Doc, Cyberdog, Apple Guide, and Rhapsody are now collector's items.
He has worked as a developer and manager for companies such as the Federal
Reserve Bank of New York (monetary policy and bank supervision), Prodigy
(early Web browser), Apple (information systems), New York State Department
of Health (rabies and lead poisoning), The Johnson Company (office manage-
ment), and Young & Rubicam (media planning and new product development).
His interests in new forms of technical training have led him to MediaSchool
(http://www.mediaschool.com), for which he has authored several Mac OS X
courses available over the Internet, as well as to Geek Cruises' Mac Mania cruise
to Alaska. He is also the first author of a technical book to be published both on
paper and on an e-book.
Active in the community, he is President of the Mid-Hudson Library System,
Chair of the Philmont Comprehensive Plan Board, founder of the Philmont Main
Street Committee, and Treasurer of the HB Playwrights Foundation.
He lives 100 miles north of New York City in the Village of Philmont with a res-
cued greyhound and a cat. His research into iMovie, iDVD, and Image Capture
has earned him the sobriquet "The Digital Scourge of Philmont."