Chapter 11. Cocoa’s Multiple-Document Architecture

Document-based applications are one of the more common types of applications developed today. They provide a framework for generating identically contained, but uniquely composed, sets of data that can be stored in files. Word processors and spreadsheet applications are two well-known examples of document-based applications. Before investigating how document-based applications are structured, let’s consider exactly what such an application does. It:

  • Creates new documents

  • Opens existing documents that are stored in files

  • Saves documents under user-designated names and locations

  • Reverts to saved documents

  • Closes documents (usually after prompting the user to save changes)

  • Prints documents and allows the page layout to be modified

  • Represents data of different types internally

  • Monitors and sets the document’s edited status and validates menu items

  • Manages document windows, including setting the window titles

  • Handles application and window delegation methods (such as when the application terminates)

Cocoa’s remarkable multiple-document architecture consists of a set of three classes—NSDocument, NSDocumentController, and NSWindowController—which provide the features in the preceding list almost entirely “for free.” Using the multiple-document architecture drastically simplifies the work developers must do to implement a multidocument application. Once you understand how the architecture works, you can have a multidocument application up and running, literally in minutes.

This chapter begins with an overview of Cocoa’s multiple-document architecture and explains the interactions between NSDocument, NSDocumentController, and NSWindowController. The final part of the chapter guides you through the implementation of a simple multidocument RTF text-editing application.

Architectural Overview

From a user’s perspective, a document is a unique body of information usually contained in its own window. Users can create an unlimited number of documents and save each to a file.

From a programming perspective, a document comprises the objects and resources unarchived from an auxiliary nib file and the controller object that loads and manages these things. This document controller is the owner of the auxiliary nib file containing the document interface and related resources. To manage a document, the document controller makes itself the delegate of its window and its “content” objects. It tracks edited status, handles window-close events, and responds to other conditions.

When users choose the New (or equivalent) command, a method is invoked in the application’s controller object. In this method, the application controller creates a document-controller object that loads the document nib file in the course of initializing itself. A document thus remains independent of the application’s “core” objects, storing state data in the document controller. If the application needs information about a document’s state, it can query the document controller.

When users choose the Save command, the application displays a Save panel and enables users to save the document in the file system. When users choose the Open command, the application displays an Open panel, allowing users to select a document file and open it.

Three Application Kit classes provide an architecture for document-based applications. These classes are NSDocumentController, NSDocument, and NSWindowController. Objects of these classes divide and orchestrate the work of creating, saving, opening, and managing the documents of an application. They are tiered in a one-to-many relationship, as depicted in Figure 11.1.

NSDocument, NSDocumentController, and NSWindowController relationships

Figure 11-1. NSDocument, NSDocumentController, and NSWindowController relationships

Multidocument applications have one NSDocumentController, which creates and manages potentially many NSDocument objects (one for each New or Open operation). In turn, an NSDocument object creates and manages one or more NSWindowController objects, one for each of the windows displayed for a document. Some objects also have responsibilities analogous to NSApplication and NSWindow delegates. NSDocument, NSDocumentController, and NSWindowController can be, but are not by default, the delegate of the application or windows.

In addition to these three Application Kit classes, the multiple-document architecture uses information in the application’s info property list to determine what types of data the application can work with. The information is stored in the property list as an array of document types. Each document type entry in the array includes the following information (packaged as a dictionary):

  • The name of the document type

  • An array of filename extensions such as rtf and txt that correspond to a document’s data type

  • An array of Mac OS-style type identifiers such as TEXT and PICT, which also correspond to a document’s data type

  • A string that determines the role of the application when interacting with the data. An application can be an Editor or a Viewer for a given data type

  • The name of the NSDocument subclass in your application that handles the data type

The application’s NSDocumentController uses the information from the info property list to do several things for you. It:

  • Automatically filters out inappropriate file types when presenting an open dialog box

  • Instantiates the appropriate NSDocument subclass for a data type

  • Prevents the user from saving documents of a specific type

Project Builder provides a simple user interface for creating and editing entries in an application’s document type array, so there’s no need to modify the property list directly.

The Role of NSDocumentController

The primary job of an application’s NSDocumentController object is to create and open documents and to track and manage these documents. The NSDocumentController maintains an internal list of document objects and tracks the current document (the document whose window is currently key). NSDocumentController is hardwired to respond appropriately to certain application events, such as when the application starts up, when it terminates, when the system powers off, and when documents are opened or printed from the Finder. For example, when a user chooses New from the File menu, an NSDocumentController:

  1. Allocates an instance of the NSDocument subclass specified in the first entry in the application’s document type array

  2. Initializes the instance by invoking your NSDocument subclass’s init method

When the user chooses Open from the File menu, an NSDocumentController:

  1. Displays the Open panel, filtering the file list using the data type(s) from the application’s info property list (Info.plist), and gets the user’s selection

  2. Uses type information from the file and data to allocate an instance of the appropriate NSDocument subclass

  3. Initializes the object by invoking its initWithContentsOfFile:ofType:, which causes the contents of the file to be loaded into the document instance

If you wish, you can make a custom document controller and implement the delegate methods invoked as a result of the same events. However, the default NSDocumentController object is an adequate application controller for most situations, and you should not need to subclass it. If you require additional behavior, such as displaying About panels and handling application preferences, it is recommended that a custom controller object rather than a subclass of NSDocumentController perform these duties.

The Role of NSDocument

The primary job of an NSDocument object is to represent, manipulate, store, and load the persistent data associated with a document. Based on the document types it claims to understand (as specified in the DocumentTypes array in the info property list), a document object must be prepared to:

  • Provide other objects in the application the data displayed in its window(s). The document object must be able to provide the data in any of the supported formats.

  • Load data into internal data structures and display it in windows. The document object must be able to accept the data in any of the supported formats.

  • Store document data in a file at a specified location in the file system.

  • Read document data stored in a file.

With the assistance of its window controllers, an NSDocument manages the display and capture of the data in its windows. By some special hardwiring of the Application Kit, the NSDocument associated with the key window is made the recipient of first responder action messages when users save, print, revert, and close documents. It also knows how to run and manage the Save panel and the Page Layout panel.

A fully implemented NSDocument knows how to track its edited status, print document data, and perform undo and redo operations. As you’ll discover as you work through the tutorials in Chapter 12 and Chapter 13, these behaviors aren’t provided completely by default, but NSDocument does go a long way to assist you in implementing each.

For edited-status tracking, NSDocument provides an API for updating a document change counter. For undo/redo operations, NSDocument creates an NSUndoManager when one is requested, responds appropriately to Undo and Redo menu commands, and updates the change counter when undo and redo operations are performed.

NSDocument facilitates the display of the Page Layout panel and the subsequent modification of the NSPrintInfo object used in printing.

The Role of NSWindowController

NSWindowController manages one window associated with a document, which is usually stored in a nib file. If a document had multiple windows, each window would have its own window controller. For example, a document might have a main data-entry window and a window listing records for selection; each window would have its own NSWindowController. When requested by its owning NSDocument, an NSWindowController loads the nib file containing a window and displays it. It also assumes responsibility for properly closing windows (after ensuring that they are saved).

Subclasses of NSWindowController are optional. Applications can often use the default instance. Subclasses can augment NSWindowControllers to perform different nib-loading and setup tasks or to customize the titles of windows.

Some applications may want to subclass NSWindowController to move the user-interface-specific logic out of the NSDocument class so it can concentrate on model-specific functionality. The Sketch application in /Developer/Examples/AppKit uses this technique.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.62.160