Cocoa has two object-oriented frameworks: Foundation
Foundation.framework) and Application Kit
AppKit.framework), as shown in Figure 1.2.
The classes in Foundation provide objects and functionality that are the basis, or “foundation,” of Cocoa. The classes in Application Kit furnish the objects and behavior that your users see in the user interface, such as windows and buttons, and handle their mouse clicks and key presses. The Application Kit depends directly on Foundation.
The Foundation framework defines a base layer of Objective-C classes. Besides providing a set of useful primitive object classes, it introduces several paradigms that define functionality not covered by the Objective-C language (detailed in Chapter 3). The Foundation Framework is designed with these goals in mind:
Provide a set of basic utility classes.
Make software development easier by introducing consistent conventions for paradigms such as memory management.
Support Unicode strings, object persistence, and file management.
The Foundation framework includes the root object class, classes representing basic data types such as strings and byte arrays, collection classes for storing other objects, classes representing system information like dates and classes representing communication ports. Figure 1.3 shows the features provided by Foundation.
The Foundation framework introduces several paradigms to avoid confusion in common situations and to introduce a level of consistency across class hierarchies. This is done with some standard policies, such as that for object ownership (who is responsible for disposing of objects), and with abstract classes that enumerate over collections. These paradigms reduce the number of special and exceptional cases in API and allow you to code more efficiently by reusing the same mechanisms with various kinds of objects.
The following sections cover some of the highlights of the Foundation framework.
Cocoa’s Foundation framework provides many basic data types, including strings, arrays, dictionaries, and numbers. Foundation furnishes several classes whose purpose is to hold other objects—the collection classes. You’ll learn more about these data types throughout the chapters in this book.
Foundation also provides functions for byte swapping, as well as classes for parsing and exception handling.
Sets are unordered collections of distinct elements.
Counted sets are sets that can contain duplicate (nondistinct) elements; these duplicates are tracked through a counter. Use sets when the speed of membership testing is important.
Collection objects provide a valuable way to store data. When you store (or archive) a collection object in the file system, its constituent objects are also stored.
The collection classes come in two versions: mutable and immutable. The mutable versions of these classes allow you to add and remove objects programmatically after the collection object is created; the immutable versions do not.
Cocoa collections are all dynamically growable.
The collection classes are discussed in greater detail in Chapter 6.
String objects represent character strings. Almost all text
in an application—from labels to spreadsheet entries to word-processing
documents—uses strings. Specifically, NSStrings (or string objects)
supplant that familiar C programming data type,
char *. String objects contain Unicode characters
rather than the narrow range of characters afforded by the ASCII
character set. Hence, they can represent words in Chinese, Arabic,
and many other languages.
Data objects are object-oriented wrappers for byte buffers. Data objects let simple allocated buffers (that is, data with no embedded pointers) take on the behavior of Foundation objects. Data objects are typically used for data storage and are also useful in applications in which data contained in data objects can be copied or moved between applications.
Data objects can wrap data of any size. When the data size is more than a few memory pages, virtual memory management is used. A data object can also wrap existing data, regardless of how the data was allocated. The object contains no information about the data itself (such as its type); the responsibility for deciding how to use the data lies with the client. For typed data, there are value objects.
A value object is a simple container for a single data item. It can hold any of the scalar types, such as integers, floats, and characters, as well as pointers, structures, and object addresses. The purpose of these objects is to allow items of such data types to be added to collections, which require their elements to be objects.
String scanning interprets and converts the characters of a string into number and string values. The scanner progresses through the characters of the string from beginning to end as you request items from it.
While scanning, you can change the scan location to rescan a portion of the string after an error or to skip ahead a certain number of characters. You can also configure a scanner to skip a set of characters or to consider or ignore case.
An exception is a special condition that interrupts the normal flow of program execution. Each application can interrupt the program for different reasons. For example, one application might interpret saving a file in a directory that’s write-protected as an exception. In this sense, the exception is equivalent to an error. Foundation provides the functionality to implement exception handling and obtain information about an exception.
Foundation provides you with classes to access core operating system functionality, such as locks, threads, and timers. These services all work together to create a robust environment for your application to run in.
The notification-related classes implement a system for broadcasting notifications of changes within an application. Any object can specify and post a notification, and any other object can register itself as an observer of that notification. Notifications are discussed in greater detail in Chapter 8.
A thread is an executable unit. A task is made up of one or more threads. Each thread has its own execution stack and is capable of independent input/output. All threads share the virtual memory address space and communication rights of their task. When a thread is started, it is detached from its initiating thread. The new thread runs independently. That is, the initiating thread does not know the new thread’s state. Different threads can run on different CPUs on multiprocessor systems, even if both threads are running inside the same task.
A lock is used to coordinate the operation of multiple threads of execution within the same application. A lock can be used to mediate access to an application’s global data or to protect a critical section of code, allowing it to run atomically—meaning that, at any given time, only one of the threads can access the protected resource.
Using tasks, your program can run another program as a subprocess and monitor that program’s execution. A task creates a separate executable entity; it differs from a thread in that it does not share memory space with the process that creates it.
A port represents a communication channel to or from another port, which typically resides in a different thread or task. The distributed objects system uses ports to send messages back and forth between threads or tasks.
The run loop is the programmatic interface to objects managing input sources. A run loop processes input for sources such as mouse and keyboard events from the window system, ports, timers, and other connections.
Because of Foundation, your application doesn’t need to either create or explicitly manage run loops. Each thread has a run loop automatically created for it. Each process begins with a default thread and therefore has a default run loop. Application Kit handles running the main thread’s run loop, but other threads’ run loops must be run manually.
You use timers to send a message to an object at specific intervals. For example, you could create a timer to tell a window to update itself after a certain time interval. Timers are discussed further in Chapter 13.
Memory management ensures that objects are properly deallocated when they’re no longer needed. This mechanism, which depends on general conformance to a policy of object ownership, automatically tracks objects that are marked for release and deallocates them at the close of the current run loop. Understanding memory management is important in creating successful Cocoa applications and is discussed in greater detail in Chapter 6.
Serializers make it possible to represent the data an object contains in an architecture-independent format, allowing sharing of data across applications. Coders take this process a step further by storing class information along with the data, thereby enabling archiving and distribution.
Archiving stores encoded objects and other data in files. Distribution is the transmission of encoded object data between different processes, threads, or even machines.
You’ll use archiving later in Chapter 9.
URLs can be used to refer to files and are, in fact, the preferred way to do so. Cocoa objects that can read or write data from or to a file can usually accept a URL in addition to a pathname as the file reference.
The Application Kit is a framework containing all objects you need to implement your graphical, event-driven user interface: windows, panels, buttons, menus, scrollers, and text fields, among others. The Application Kit handles all the details for you as it efficiently draws on the screen, communicates with hardware devices and screen buffers, clears areas of the screen before drawing, and clips views. Figure 1.4 shows the Application Kit’s conceptual class hierarchy.
The more than one hundred classes in the Application Kit may seem daunting at first. However, most Application Kit classes are support classes that you use indirectly. The sections that follow briefly cover Application Kit’s architectural highlights.
Your user interface is how the user interacts with your application. You can create and manage the windows, dialog boxes, menus, pop-up lists, and other controls provided by Application Kit. You’ll be using many user interface elements in the tutorials later in the book.
The two principal functions of a window are to provide an area in which views can be placed and to accept and distribute (to the appropriate views) events the user causes through actions with the mouse and keyboard.
You typically set up windows using Interface Builder, which allows you to position them, set up many of their visual and behavioral attributes, and lay out views in them. The programmatic work you do with windows more often involves bringing them on and off the screen; changing dynamic attributes, such as the window’s title; and monitoring certain window actions, such as closing, zooming, and resizing.
A view is an abstract representation for all objects displayed in a window. Views provide the structure for drawing, printing, and handling events. Views are arranged within a window in a nested hierarchy of subviews.
Panels are a type of window that you use to display transient, global, or pressing information. For example, you would use a panel rather than a window to display error messages or to query the user for a response to remarkable or unusual circumstances. The Application Kit implements some common panels for you, such as the Save, Open, and Print panels, used to save, open, and print documents. Using these panels gives the user a consistent look and feel across applications for common operations.
Cocoa provides a common set of user interface objects such as buttons, sliders, and browsers that you can manipulate graphically to control some aspect of your application. Just what a particular item does is up to you. You typically use Interface Builder to lay out your interface. The following list describes only a few of the widgets provided by the Application Kit:
Menus and cursors. The menu and cursor classes define the look and behavior of the menus and cursors that your application displays to the user.
Tables. Tables display data in row and column form. Tables are ideal for, but not limited to, displaying database records, in which a row corresponds to each record and columns contain record attributes. The user can edit individual cells and rearrange the columns.
Buttons. A button is a user interface object that sends a message to another object when clicked. You can create a single button, such as a push button, or a group of related buttons, such as a group of switches or radio buttons.
In addition to these widgets, Cocoa provides sheets, sliders, drawers, and toolbars, to name just a few.
Text fields implement a simple editable text field, and a text view provides more comprehensive editing features for larger text bodies. A Font panel allows users to customize fonts appearing in their text views.
Images encapsulate graphics data, allowing you to easily and efficiently access images stored in files on the disk and displayed on the screen. You do not need to know how to draw images of different formats because Cocoa handles this for you.
Color is supported by a variety of classes representing colors and color views. There is a rich set of color formats and representations, including custom ones. Cocoa color classes automatically handle different color spaces. The color support classes define and present panels and views that allow the user to select and apply colors. For example, the user can drag colors from the Color panel to any color well. You can also extend the standard Color panel.
Document-based applications, e.g., word processing and spreadsheet applications, are some of the more common types of applications developed today. Word processors and spreadsheet applications are two well-known examples of document-based applications.
Various Application Kit classes provide an architecture for document-based applications that simplifies the work you must do to implement the features listed in the previous section. These classes divide and orchestrate the work of creating, saving, opening, and managing the documents of an application. The document architecture is discussed in more detail in Chapter 11.
A responder chain is an ordered list of objects that respond to user events. When the user clicks the mouse or presses a key, an event is generated and the Application Kit searches in a specific order for an object that can “respond” to it. Understanding the flow of control in your application is discussed in Chapter 8.
The pasteboard is a repository for data that’s copied from your application, and it makes this data available to any application that cares to use it. The pasteboard implements the familiar cut-copy-paste and drag-and-drop operations.
File wrappers correspond to files or directories on disk. A file wrapper holds the contents of the file in memory so that it can be displayed, changed, or transmitted to another application. It also provides an icon for dragging the file or representing it as an attachment. A file manager can be used to access and enumerate file and directory contents. The Open and Save panels also provide a convenient and familiar user interface to the file system.
A spell server lets you define a spellchecking service and provide it to other applications. To connect your application to a spellchecking service, you use a spellchecker. Cocoa’s text system provides automatic spellchecker integration.
If an application is to be used in more than one part of the world,
its resources may need to be customized, or “localized,” for language,
country, or cultural region. For example, an application may need to
have separate Japanese, English, French, and German versions of
character strings, icons, user interface definitions, or context
help. Resource files specific to a particular language are grouped
together in a subdirectory of the bundle directory (the directories
.lproj extension). The localized resources
that are appropriate to the user’s preferences are then dynamically
loaded into your application when it is launched.