Top Banner
Mac OS X App Programming Guide General 2011-06-27
92
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: MOSXAppProgrammingGuide

Mac OS X App Programming GuideGeneral

2011-06-27

Page 2: MOSXAppProgrammingGuide

Apple Inc.© 2011 Apple Inc.All rights reserved.

No part of this publication may be reproduced,stored in a retrieval system, or transmitted, inany form or by any means, mechanical,electronic, photocopying, recording, orotherwise, without prior written permission ofApple Inc., with the following exceptions: Anyperson is hereby authorized to storedocumentation on a single computer forpersonal use only and to print copies ofdocumentation for personal use provided thatthe documentation contains Apple’s copyrightnotice.

The Apple logo is a trademark of Apple Inc.

No licenses, express or implied, are grantedwith respect to any of the technology describedin this document. Apple retains all intellectualproperty rights associated with the technologydescribed in this document. This document isintended to assist application developers todevelop applications only for Apple-labeledcomputers.

Apple Inc.1 Infinite LoopCupertino, CA 95014408-996-1010

.Mac is a registered service mark of Apple Inc.

App Store is a service mark of Apple Inc.

Apple, the Apple logo, Bonjour, Cocoa, eMac,Finder, Instruments, iPhoto, iTunes, Keychain,Mac, Mac OS, Macintosh, Objective-C,QuickDraw, Sand, Spotlight, Time Machine, andXcode are trademarks of Apple Inc., registeredin the United States and other countries.

IOS is a trademark or registered trademark ofCisco in the U.S. and other countries and is usedunder license.

OpenGL is a registered trademark of SiliconGraphics, Inc.

UNIX is a registered trademark of The OpenGroup

Even though Apple has reviewed this document,APPLE MAKES NO WARRANTY OR REPRESENTATION,EITHER EXPRESS OR IMPLIED, WITH RESPECT TOTHIS DOCUMENT, ITS QUALITY, ACCURACY,MERCHANTABILITY, OR FITNESS FOR A PARTICULARPURPOSE. AS A RESULT, THIS DOCUMENT ISPROVIDED “AS IS,” AND YOU, THE READER, AREASSUMING THE ENTIRE RISK AS TO ITS QUALITYAND ACCURACY.

IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT,INDIRECT, SPECIAL, INCIDENTAL, OR

CONSEQUENTIAL DAMAGES RESULTING FROM ANYDEFECT OR INACCURACY IN THIS DOCUMENT, evenif advised of the possibility of such damages.

THE WARRANTY AND REMEDIES SET FORTH ABOVEARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORALOR WRITTEN, EXPRESS OR IMPLIED. No Appledealer, agent, or employee is authorized to makeany modification, extension, or addition to thiswarranty.

Some states do not allow the exclusion or limitationof implied warranties or liability for incidental orconsequential damages, so the above limitation orexclusion may not apply to you. This warranty givesyou specific legal rights, and you may also haveother rights which vary from state to state.

Page 3: MOSXAppProgrammingGuide

Contents

Introduction About Mac OS X Application Design 9

At a Glance 9Cocoa Helps You Create Great Applications for Mac OS X 9The Document Architecture Enables Document-Based Applications 10Common Behaviors Make Applications Complete 10Get It Right: Meet System and App Store Requirements 10Finish Your Application with Performance Tuning 10

How to Use This Document 11See Also 11

Chapter 1 The Application Runtime Environment 13

An Environment Designed for Ease of Use 13A Sophisticated Graphics Environment 14Low-Level Details of the Runtime Environment 14

Based on UNIX 15Concurrency and Threading 15The File System 16Security 19

Chapter 2 The Core Application Design 23

Fundamental Design Patterns 23The Application Style Determines the Core Architecture 25

The Core Objects for All Cocoa Applications 27Additional Core Objects for Multiwindow Applications 30Shoebox Applications Should Not Use NSDocument 31

The Application Life Cycle 31The main Function is the Application Entry Point 32The Application’s Main Event Loop Drives Interactions 33Automatic and Sudden Termination of Applications Improve the User Experience 34

Support the Key Runtime Behaviors in Your Applications 35Automatic Termination 35Sudden Termination 36User Interface Preservation 37

Applications Are Built Using Many Different Pieces 42The User Interface 42Event Handling 43Graphics, Drawing, and Printing 45Text Handling 45

Implementing the Application Menu Bar 46

32011-06-27 | © 2011 Apple Inc. All Rights Reserved.

Page 4: MOSXAppProgrammingGuide

Xcode Templates Provide the Main Menu 46Connect Menu Items to Your Code or Your First Responder 47

Chapter 3 Implementing a Document-Based Design 49

Three Key Objects Support Document-Based Applications 49NSDocumentController Creates and Manages Documents 50NSDocument Presents and Stores Document Data 51NSWindowController Manages One Document Window 52

Subclassing Objects in the Document Architecture 53You Must Subclass NSDocument 53You May Want to Subclass NSWindowController 56You Rarely Need to Subclass NSDocumentController 58

Xcode Provides a Document-Based Application Template 58Supported Document Types Are Declared in the Application Property List 59Multiple Document Types Use Multiple NSDocument Subclasses 60The Document Architecture Has Built-in Undo Support 61

Implementing Undo 61Implementing Partial Undo 62Managing the Change Count 62Not Supporting Undo 62

The Document Architecture Supports Robust Error Handling 63Documents Are Automatically Saved 63Document Saving Is Asynchronous 64Users Can Browse Document Versions 65Windows Are Restored Automatically 65

Chapter 4 Implementing the Full-Screen Experience 67

Full-Screen API in NSApplication 67Full-Screen API in NSWindow 68Full-Screen API in NSWindowDelegate Protocol 68

Chapter 5 Supporting Common Application Behaviors 71

You Can Prevent the Automatic Relaunch of Your Application 71Making Your Application Accessible Enables Many Users 71Provide User Preferences for Customization 74Integrate Your App With Spotlight Search 74Use Services to Increase Your Application’s Usefulness 75Make Use of Resolution Independence 75Prepare for Fast User Switching 76Take Advantage of the Dock 77

42011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CONTENTS

Page 5: MOSXAppProgrammingGuide

Chapter 6 Build-Time Configuration Details 79

Configuring Your Xcode Project 79The Information Property List File 80The Mac OS X Application Bundle 81Internationalizing Your Application 83

Chapter 7 Tuning for Performance and Responsiveness 85

Speed Up Your Application’s Launch Time 85Delay Initialization Code 85Simplify Your Main Nib File 86Minimize Global Variables 86Minimize File Access at Launch Time 86

Don’t Block the Main Thread 87Decrease Your Application’s Code Size 87

Compiler-Level Optimizations 87Use Core Data for Large Data Sets 88Eliminate Memory Leaks 89Dead Strip Your Code 89Strip Symbol Information 89Build Fixed-Position Application Code 89

Document Revision History 91

52011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CONTENTS

Page 6: MOSXAppProgrammingGuide

62011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CONTENTS

Page 7: MOSXAppProgrammingGuide

Figures, Tables, and Listings

Chapter 1 The Application Runtime Environment 13

Table 1-1 Key directories for Mac OS X applications 16Table 1-2 Attributes for the Mac OS X file system 19Listing 1-1 Getting the path to the Application Support directory 18

Chapter 2 The Core Application Design 23

Figure 2-1 The Calculator single-window utility application 25Figure 2-2 The iPhoto single-window application 26Figure 2-3 TextEdit document window 27Figure 2-4 Key objects in a single-window application 28Figure 2-5 Key objects in a multiwindow document application 30Figure 2-6 The main event loop 33Figure 2-7 Responder objects targeted by Cocoa for preservation 38Figure 2-8 Windows and menus in an application 43Figure 2-9 Processing events in the main run loop 44Table 2-1 Fundamental design patterns used by Mac OS X applications 23Table 2-2 The core objects used by all Cocoa applications 28Table 2-3 Additional objects used by multiwindow document applications 31Listing 2-1 The main function of a Mac OS X application 32Listing 2-2 Returning the main window for a single-window application 41Listing 2-3 Providing Cocoa with an already restored window 41

Chapter 3 Implementing a Document-Based Design 49

Figure 3-1 Relationships among NSDocumentController, NSDocument, andNSWindowController objects 50

Table 3-1 Document Architecture Objects and Subclasses 53

Chapter 4 Implementing the Full-Screen Experience 67

Table 4-1 Window delegate methods supporting full-screen mode 69

Chapter 5 Supporting Common Application Behaviors 71

Figure 5-1 Universal Access system preference dialog 73Figure 5-2 Spotlight extracting metadata 75

72011-06-27 | © 2011 Apple Inc. All Rights Reserved.

Page 8: MOSXAppProgrammingGuide

Chapter 6 Build-Time Configuration Details 79

Figure 6-1 The information property list editor 80Figure 6-2 The Language preference view 84Table 6-1 A typical application bundle 81

Chapter 7 Tuning for Performance and Responsiveness 85

Table 7-1 Compiler optimization options 88

82011-06-27 | © 2011 Apple Inc. All Rights Reserved.

FIGURES, TABLES, AND LISTINGS

Page 9: MOSXAppProgrammingGuide

This document is the starting point for learning how to create Mac OS X applications. It contains fundamentalinformation about the Mac OS X environment and how your applications interact with that environment. Italso contains important information about the architecture of Mac OS X applications and tips for designingkey parts of your application.

At a Glance

Cocoa is the application environment that unlocks the full power of Mac OS X. Cocoa provides APIs, libraries,and runtimes that help you create fast, exciting applications that automatically inherit the beautiful look andfeel of Mac OS X, as well as standard behaviors users expect.

Cocoa Helps You Create Great Applications for Mac OS X

You write applications for Mac OS X using Cocoa, which provides a significant amount of infrastructure foryour program. Fundamental design patterns are used throughout Cocoa to enable your application tointerface seamlessly with subsystem frameworks, and core application objects provide key behaviors tosupport simplicity and extensibility in application architecture. Key parts of the Cocoa environment aredesigned particularly to support ease of use, one of the most important aspects of successful Mac OS Xapplications. High-quality graphics, including animation, provide immediate visual appeal as well as criticaluser feedback. In addition, the Mac OS X runtime includes many low-level features, such as preemptivemultitasking, protected memory, concurrency, powerful networking and file system access, and security.

At a Glance 92011-06-27 | © 2011 Apple Inc. All Rights Reserved.

INTRODUCTION

About Mac OS X Application Design

Page 10: MOSXAppProgrammingGuide

Relevant Chapters: “The Application Environment” (page 13) and “The Core Application Design” (page 23)

The Document Architecture Enables Document-Based Applications

A document-based application is one of the more common types of applications. Documents are datacontainers that are stored in files. Traditional word processors and spreadsheet applications are examples ofdocument-based applications. One application typically handles multiple documents, each in its own window,and often displays more than one document at a time. Cocoa provides excellent support for this designthrough a subsystem called the document architecture.

Relevant Chapter: “Implementing a Document-Based Design” (page 49)

Common Behaviors Make Applications Complete

During the design phase of creating your application, you need to think about how to implement certainfeatures that users expect in well-formed Mac OS X applications. Integrating these features into your applicationarchitecture can have an impact on the user experience: accessibility, preferences, Spotlight, services, resolutionindependence, fast user switching, and the Dock. Enabling your application to assume full-screen mode,taking over the entire screen, provides users with a more immersive, cinematic experience and enables themto concentrate fully on their content without distractions.

Relevant Chapters: “Supporting Common Application Behaviors” (page 71) and “Implementing the Full-ScreenExperience” (page 67)

Get It Right: Meet System and App Store Requirements

Configuring your application properly is an important part of the development process. Mac OS X applicationsuse a structured directory called a bundle to manage their code and resource files. And although most of thefiles are custom and exist to support your application, some are required by the system or the App Store andmust be configured properly. The application bundle also contains the resources you need to provide tointernationalize your application to support multiple languages.

Relevant Chapter: “Build-Time Configuration Details” (page 79)

Finish Your Application with Performance Tuning

As you develop your application and your project code stabilizes, you can begin performance tuning. Ofcourse, you want your application to launch and respond to the user’s commands as quickly as possible. Aresponsive application fits easily into the user’s workflow and gives an impression of being well crafted. Youcan improve the performance of your application by speeding up launch time and decreasing your application’scode footprint.

10 At a Glance2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

INTRODUCTION

About Mac OS X Application Design

Page 11: MOSXAppProgrammingGuide

Relevant Chapter: “Tuning for Performance and Responsiveness” (page 85)

How to Use This Document

This guide introduces you to the most important technologies that go into writing an application. In thisguide you will see the whole landscape of what's needed to write one. That is, this guide shows you all the"pieces" you need and how they fit together. There are important aspects of application design that thisguide does not cover, such as user interface design. However, this guide includes many links to otherdocuments that provide details about the technologies it introduces, as well as links to tutorials that providea hands-on approach.

In addition, this guide emphasizes certain technologies introduced in Mac OS X v10.7, which provide essentialcapabilities that set your application apart from older ones and give it remarkable ease of use, bringing someof the best features from iOS to Mac OS X.

See Also

The following documents provide additional information about designing Mac OS X applications, as well asmore details about topics covered in this document:

● To work through a tutorial showing you how to create a Cocoa application, see Your First Mac App.

● For information about user interface design enabling you to create effective applications using Mac OSX, see Mac OS X Human Interface Guidelines.

● For information about the design patterns used in Cocoa, see Cocoa Fundamentals Guide.

● For a general survey of Mac OS X technologies, see Mac OS X Technology Overview.

How to Use This Document 112011-06-27 | © 2011 Apple Inc. All Rights Reserved.

INTRODUCTION

About Mac OS X Application Design

Page 12: MOSXAppProgrammingGuide

12 See Also2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

INTRODUCTION

About Mac OS X Application Design

Page 13: MOSXAppProgrammingGuide

Like all modern operating systems, Mac OS X incorporates the latest technologies for creating powerful andfun-to-use applications. But the technologies by themselves are not enough to make every application great.What sets an application apart from its peers is how it helps the user achieve some tangible goal. After all,users are not going to care what technologies an application uses, as long as it helps them do what theyneed to do. An application that gets in the user’s way is going to be forgotten, but one that makes work (orplay) easier and more fun is going to be remembered.

Cocoa is the application environment that you use to write applications for Mac OS X. In its runtime aspect,Cocoa presents the application’s user interface and integrates it tightly with the other components of theoperating system. Cocoa also has a development aspect, as described in “The Core Application Design” (page23).

This chapter describes some of the key parts of the Mac OS X runtime environment that help you create greatapplications. The items described here are not a complete list but are simply a collection of some of the mostcommonly used techniques and technologies available for your applications. In particular, this chapterdescribes some of the important ease-of-use technologies introduced in Mac OS X v10.7. For a more thoroughlist of technologies available in Mac OS X, see Mac OS X Technology Overview.

An Environment Designed for Ease of Use

Mac OS X strives to provide an environment that is transparent to users and as easy to use as possible. Bymaking hard tasks simple and getting out of the way, the system makes it easier for the user to be creativeand spend less time worrying about the steps needed to make the computer work. Of course, simplifyingtasks means your application has to do more of the work, but Mac OS X provides help in that respect too.

As you design your application, you should think about the tasks that users normally perform and find waysto make them easier. Mac OS X v10.7 supports powerful ease-of-use features and design principles thataugment those introduced in earlier system versions. For example:

● Users should not have to save their work manually. The document model in Cocoa provides support forsaving the user’s file-based documents without user interaction; see “Documents Are AutomaticallySaved” (page 63).

● Applications should restore the user’s work environment at login time. Cocoa provides support forarchiving the current state of the application’s interface (including the state of unsaved documents) andrestoring that state at launch time; see “User Interface Preservation” (page 37).

● Applications should support automatic termination so that the user never has to quit them. Automatictermination means that when the user closes an application’s windows, the application appears to quitbut actually just moves to the background quietly. The advantage is that subsequent launches are nearlyinstant as the application simply moves back to the foreground; see “Automatic and Sudden Terminationof Applications Improves the User Experience” (page 34)

An Environment Designed for Ease of Use 132011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 14: MOSXAppProgrammingGuide

● You should consider providing your users with an immersive, full-screen experience by implementinga full-screen version of your user interface. The full-screen experience eliminates outside distractionsand allows the user to focus on their content; see “Implementing the Full-Screen Experience” (page 67).

● Support trackpad gestures for appropriate actions in your application. Gestures provide simple shortcutsfor common tasks and can be used to supplement existing controls and menu commands. Mac OS Xprovides automatic support for reporting gestures to your application through the normal event-handlingmechanism; see Cocoa Event-Handling Guide.

● Consider minimizing or eliminating the user’s interactions with the raw file system. Rather than exposethe entire file system to the user through the open and save panels, some applications, in the mannerof iPhoto and iTunes, can provide a better user experience by presenting the user’s content in a simplifiedbrowser designed specifically for the application’s content. Mac OS X uses a well-defined file systemstructure that allows you to place and find files easily and includes many technologies for accessingthose files; see “The File System” (page 16).

● For applications that support custom document types, provide a Quick Look plug-in so that users canview your documents from outside of your application; see Quick Look Programming Guide.

All of the preceding features are supported by Cocoa and can be incorporated with relatively little effort.

A Sophisticated Graphics Environment

High-quality graphics and animation make your application look great and can convey a lot of informationto the user. Animations in particular are a great way to provide feedback about changes to your user interface.So as you design your application, keep the following ideas in mind:

● Use animations to provide feedback and convey changes. Cocoa provides mechanisms for creatingsophisticated animations quickly in both the AppKit and Core Animation frameworks. For informationabout creating view-based animations, see Cocoa Drawing Guide. For information about using CoreAnimation to create your animations, see Core Animation Programming Guide.

● Include high-resolution versions of your art and graphics. Mac OS X automatically loads high-resolutionimage resources when an application runs on a screen whose scaling factor is greater than 1.0. Includingsuch image resources makes your application’s graphics look even sharper and crisper on thosehigher-resolution screens.

For information about the graphics technologies available in Mac OS X, see “Graphics and MultimediaTechnologies” in Mac OS X Technology Overview.

Low-Level Details of the Runtime Environment

When you are ready to begin writing actual code, there are a lot of technologies available to make your lifeeasier. Like many modern operating systems, Mac OS X supports all of the basic features such as memorymanagement, file management, networking, and concurrency that you need to write your code. In somecases, though, Mac OS X also provides more sophisticated services (or specific coding conventions) that,when followed, can make writing your code even easier.

14 A Sophisticated Graphics Environment2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 15: MOSXAppProgrammingGuide

Based on UNIX

Mac OS X is powered by a 64-bit Mach kernel, which manages processor resources, memory, and otherlow-level behaviors. On top of the kernel sits a modified version of the Berkeley Software Distribution (BSD)operating system, which provides interfaces that applications can use to interact with the lower-level system.This combination of Mach and BSD provides the following system-level support for your applications:

● Preemptive multitasking—All processes share the CPU efficiently. The kernel schedules processes in away that ensures they all receive the time they need to run. Even background applications continue toreceive CPU time to execute ongoing tasks.

● Protected memory—Each process runs in its own protected memory space, which prevents processesfrom accidentally interfering with each other. (Applications can share part of their memory space toimplement fast interprocess communication but take responsibility for synchronizing and locking thatmemory appropriately.)

● Virtual memory—64-bit applications have a virtual address space of approximately 18 exabytes (18billion billion bytes). (If you create a 32-bit application, the amount of virtual memory is only 4 GB.) Whenan application’s memory usage exceeds the amount of free physical memory, the system transparentlywrites pages to disk to make more room. Written out pages remain on disk until they are needed inmemory again or the application exits.

● Networking and Bonjour—Mac OS X provides support for the standard networking protocols andservices in use today. BSD sockets provide the low-level communication mechanism for applications,but higher-level interfaces also exist. Bonjour simplifies the user networking experience by providing adynamic way to advertise and connect to network services over TCP/IP.

For detailed information about the underlying environment of Mac OS X, see “Kernel and Device DriversLayer” in Mac OS X Technology Overview.

Concurrency and Threading

Each process starts off with a single thread of execution and can create more threads as needed. Althoughyou can create threads directly using POSIX and other higher-level interfaces, for most types of work it isbetter to create them indirectly using block objects with Grand Central Dispatch (GCD) or operation objects,a Cocoa concurrency technology implemented by the NSOperation class.

GCD and operation objects are an alternative to raw threads that simplify or eliminate many of the problemsnormally associated with threaded programming, such as synchronization and locking. Specifically, theydefine an asynchronous programming model in which you specify only the work to be performed and theorder in which you want it performed. The system then handles the tedious work required to schedule thenecessary threads and execute your tasks as efficiently as possible on the current hardware. You should notuse GCD or operations for work requiring time-sensitive data processing (such as audio or video playback),but you can use them for most other types of tasks.

For more information on using GCD and operation objects to implement concurrency in your applications,see Concurrency Programming Guide.

Low-Level Details of the Runtime Environment 152011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 16: MOSXAppProgrammingGuide

The File System

The file system in Mac OS X is structured to provide a better experience for users. Rather than exposing theentire file system to the user, the Finder hides any files and directories that an average user should not needto use, such as the contents of low-level UNIX directories. This is done to provide a simpler interface for theend user (and only in places like the Finder and the open and save panels). Applications can still access anyfiles and directories for which they have valid permissions, regardless of whether they are hidden by theFinder.

When creating applications, you should understand and follow the conventions associated with the Mac OSX file system. Knowing where to put files and how to get information out of the file system ensures a betteruser experience.

A Few Important Application Directories

The Mac OS X file system is organized in a way that groups related files and data together in specific places.Every file in the file system has its place and applications need to know where to put the files they create.This is especially important if you are distributing your application through the App Store, which expectsyou to put your application’s data files in specific directories.

Table 1-1 lists the directories with which applications commonly interact. Directories preceded with a tilde(~) character indicate a path inside the home directory, which can be either the user’s home directory or theapplication’s container directory if the application is in a sandbox (as described in “The App Sandbox” (page19)). Because the actual paths can differ based on the conditions, use the URLsForDirectory:inDomains:method of the NSFileManager class to retrieve the actual directory path. You can then add any customdirectory and filename information to the returned URL object to complete the path.

Table 1-1 Key directories for Mac OS X applications

DescriptionDirectory

This is the installation directory for your application bundle. The path for the globalapplication’s directory is /Applications but each user directory may have a localapplications directory containing user-specific applications. Regardless, you should notneed to use this path directly. To access resources inside your application bundle, usean NSBundle object instead.

For more information about the structure of your application bundle and how you locateresources, see “The Mac OS X Application Bundle” (page 81).

Applicationsdirectory

The configuration of your application determines the location of the home directory seenby your application: ● For applications running in a sandbox in Mac OS X 10.7 and later, the home directory

is the application’s container directory. For more information about the containerdirectory, see “The Container Directory Is Your Application’s Home Directory” (page20).

● For applications running outside of a sandbox (including those running in versionsof Mac OS X before 10.7), the home directory is the user-specific subdirectory of/Users that contains the user’s files.

To retrieve the path to the home directory, use the NSHomeDirectory function.

Home directory

16 Low-Level Details of the Runtime Environment2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 17: MOSXAppProgrammingGuide

DescriptionDirectory

The Library directory is the top-level directory for storing private application-related dataand preferences. There are several Library directories scattered throughout the systembut you should always use the one located inside the current home directory.

Do not store files directly at the top-level of the Library directory. Instead, store them inone of the specific subdirectories described in this table.

In Mac OS X 10.7 and later, the Finder hides the Library directory in the user’s home folderby default. Therefore, you should never store files in this directory that you want the userto access.

To get the path to this directory use the NSLibraryDirectory search path key withthe NSUserDomainMask domain.

Library directory

The Application Support directory is where your application stores any type of file thatsupports the application but is not required for the application to run, such as documenttemplates or configuration files. The files should be application-specific but should neverstore user data. This directory is located inside the Library directory.

Never store files at the top level of this directory: Always put them in a subdirectorynamed for your application or company.

If the resources apply to all users on the system, such as document templates, place themin /Library/Application Support. To get the path to this directory use theNSApplicationSupportDirectory search path key with the NSLocalDomainMaskdomain. If the resources are user-specific, such as workspace configuration files, placethem in the current user’s ~/Library/Application Support directory. To get thepath to this directory use the NSApplicationSupportDirectory search path key withthe NSUserDomainMask domain.

ApplicationSupportdirectory

The Caches directory is where you store cache files and other temporary data that yourapplication can re-create as needed. This directory is located inside the Library directory.

Never store files at the top level of this directory: Always put them in a subdirectorynamed for your application or company. Your application is responsible for cleaning outcache data files when they are no longer needed. The system does not delete files fromthis directory.

To get the path to this directory use the NSCachesDirectory search path key with theNSUserDomainMask domain.

Caches directory

The Movies directory contains the user’s video files.

To get the path to this directory use the NSMoviesDirectory search path key with theNSUserDomainMask domain.

Movies directory

The Music directory contains the user’s music and audio files.

To get the path to this directory use the NSMusicDirectory search path key with theNSUserDomainMask domain.

Music directory

The Pictures directory contains the user’s images and photos.

To get the path to this directory use the NSPicturesDirectory search path key withthe NSUserDomainMask domain.

Picturesdirectory

Low-Level Details of the Runtime Environment 172011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 18: MOSXAppProgrammingGuide

DescriptionDirectory

The Temporary directory is where you store files that do not need to persist betweenlaunches of your application. You normally use this directory for scratch files or othertypes of short-lived data files that are not related to your application’s persistent data.This directory is typically hidden from the user.

Your application should remove files from this directory as soon as it is done with them.The system may also purge lingering files from this directory at system startup.

To get the path to this directory use the NSTemporaryDirectory function.

Temporarydirectory

Listing 1-1 shows an example of how to retrieve the base path to the Application Support directory andthen append a custom application directory to it.

Listing 1-1 Getting the path to the Application Support directory

NSFileManager* fileManager = [NSFileManager defaultManager];NSURL* appSupportDir = nil;

NSArray *urls = [fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask];if ([paths count] > 0) { appSupportDir = [[urls objectAtIndex:0] URLByAppendingPathComponent:@"com.example.MyApp"];}

For more information about how to access files in well known system directories, see Low-Level FileManagementProgramming Topics.

Coordinating File Access with Other Processes

In Mac OS X, other processes may have access to the same files that your application does. Therefore, whenworking with files, you should use the file coordination interfaces introduced in Mac OS X v10.7 to be notifiedwhen other processes (including the Finder) attempt to read or modify files your application is currentlyusing.

The file coordination APIs allow you to assert ownership over files and directories that your application caresabout. Any time another process attempts to touch one of those items, your application is given a chanceto respond. For example, when an application attempts to read the contents of a document your applicationis editing, you can write unsaved changes to disk before the other process is allowed to do its reading.

For information about how to use the file coordination interfaces, see Foundation Release Notes.

Interacting with the File System

Disks in Macintosh computers are formatted using the HFS+ file system by default. However, Macintoshcomputers can interact with disks that use other formats so you should never code specifically to any onefile system. Table 1-2 lists some of the basic file system attributes you may need to consider in your applicationand how you should handle them.

18 Low-Level Details of the Runtime Environment2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 19: MOSXAppProgrammingGuide

Table 1-2 Attributes for the Mac OS X file system

DescriptionAttribute

The HFS+ file system is case-insensitive but also case-preserving. Therefore, whenspecifying filenames and directories in your code, it is best to assume case-sensitivity.

Case sensitivity

Construct paths using the methods of the NSURL and NSString classes. The NSURLclass is preferred for path construction because of its ability to specify not only pathsin the local file system but paths to network resources.

Path construction

Many file-related attributes can be retrieved using the getResourceValue:forKey:error: method of the NSURL class. You can also use an NSFileManagerobject to retrieve many file-related attributes.

File attributes

File permissions are managed using access control lists (ACLs) and BSD permissions.The system uses ACLs whenever possible to specify precise permissions for files anddirectories, but it falls back to using BSD permissions when no ACLs are specified.

By default, any files your application creates are owned by the current user and givenappropriate permissions. Thus, your application should always be able to read andwrite files it creates explicitly. In addition, the application’s sandbox may allow it toaccess other files in specific situations. For more information about the sandbox, see“The App Sandbox” (page 19).

File permissions

Applications that cannot use the File Coordination interfaces (see “Coordinating FileAccess with Other Processes” (page 18)) to track changes to files and directories canuse the FSEvents API instead. This API provides a lower-level interface for tracking filesystem interactions and is available in Mac OS X v10.5 and later.

For information on how to use the FSEvents API, see File System Events ProgrammingGuide.

Tracking filechanges

Security

The security technologies in Mac OS X help you secure sensitive data created or managed by your applicationand also help minimize the damage caused by successful exploits.

The Keychain

A keychain is a secure, encrypted container for storing the user’s passwords and other secrets. Users oftenhave to manage multiple accounts that require logins with user IDs and passwords.

For more on the keychain, see “Keychain Services Concepts” in Keychain Services Programming Guide.

The App Sandbox

In Mac OS X v10.7 and later, placing your application in an app sandbox is a great way to minimize thepotential damage caused by successful exploits. Even the best code can have flaws that lead to potentialsecurity breaches. For your application to provide the highest level of security:

● Adopting a sandbox is the best practice.

Low-Level Details of the Runtime Environment 192011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 20: MOSXAppProgrammingGuide

● An application should adopt the tightest sandbox possible.

An app sandbox prevents the code involved in those breaches from taking advantage of your application’sstatus as a user process to gain access to other parts of the system or to other unrelated (but potentiallyenticing) user data. It prevents these exploits by limiting access to unrelated files and by limiting access tosystem resources (such as the network or specific hardware) that your application does not use.

An app sandbox comprises two key components:

● Entitlements for declaring the resources that the application uses

● A container directory for storing the application’s files

You must specifically request that your application be put into a sandbox by signing it with at least theminimal set of entitlements. When the sandboxing entitlements are present, the system automatically createsa container directory for the application and runs it inside of an appropriately configured sandbox.

Entitlements Declare the System Resources Your Application Needs

Entitlements let the system know both that you want your application placed in a sandbox and that yourapplication needs access to specific resources while in that sandbox. You specify the entitlements for yourapplication using an entitlements property-list file that you create in Xcode and keep with your project.Before distributing your application (or submitting it to the App Store), you sign your application with thisentitlements file. The codesign command-line tool embeds your entitlements into the application’s signature.When the user subsequently launches your application, the system retrieves the entitlements from thesignature and uses them to configure your application’s sandbox.

To request that your application be placed in a sandbox, you must include the following key in yourentitlements property-list file at a minimum:

com.apple.security.app-sandbox

In addition to including the preceding key, your entitlements property-list file should include the other keysthat reflect which resources your application uses. An application can request access to the Open and Savepanels, access to the network, access to a camera (when present), and access to the microphone. You mustrequest the items that your application uses but should not request access to items your application doesnot use. If you attempt to use a feature for which you do not have an appropriate entitlement, the systemdenies access and logs an appropriate message to the console. You can use these console messages duringdebugging to help identify features your application uses.

For a complete list of entitlement keys and information on how to create an entitlements property-list fileand apply it to your application, see Code Signing Guide.

The Container Directory Is Your Application’s Home Directory

A container directory is where a sandboxed application stores all of its private files and data. Systemframeworks use this directory when writing out application-specific data such as preferences and autosaveinformation. Your application similarly uses this directory to store cache files, temporary data files, or anyfiles that the user would not normally see. The only thing you do not store in the container directory are filesthat the user explicitly saves using the system Save panel.

20 Low-Level Details of the Runtime Environment2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 21: MOSXAppProgrammingGuide

Applications in a sandbox are specifically prohibited from accessing files outside the container directory withsome exceptions. An application may work with files opened using the system Open panel or saved usingthe system Save panel. In such a situation, the app sandbox is modified to allow access to those specific files.Similarly, the use of established system interfaces may also give your application indirect access to data inother parts of the file system. For example, the Address Book framework gives you access to the user’s contactinformation, which is stored outside of your application sandbox.

The first time your application is launched, the system creates the container directory automatically in theuser’s ~/Library/Containers directory and uses your application’s bundle identifier for the directoryname. For example, the container directory for the TextEdit application is~/Library/Containers/com.apple.TextEdit.

Note: Although the directory name is derived from the bundle identifier of the application, ownership of thedirectory is linked to your developer identity for security. Using the developer identity means that maliciousapplications cannot try to spoof the system into granting access to your container using your bundle identifier.

The structure of the sandbox directory loosely parallels the structure of the user’s home directory. To retrievethe path to directories in your sandbox, you must always use system-provided methods such as theURLsForDirectory:inDomains:method of NSFileManager. Never try to build paths to these directoriesmanually. Doing so will cause your application to break if the location of the paths changes later. For moreinformation about the directories you should be using in your applications, see “A Few Important ApplicationDirectories” (page 16).

Low-Level Details of the Runtime Environment 212011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 22: MOSXAppProgrammingGuide

22 Low-Level Details of the Runtime Environment2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 1

The Application Runtime Environment

Page 23: MOSXAppProgrammingGuide

To connect with the power of Mac OS X, you develop applications using the Cocoa application environment.Cocoa has a runtime aspect and a development aspect. In its runtime aspect, Cocoa presents the application’suser interface and integrates it tightly with the other components of the operating system. In its developmentaspect, Cocoa for Mac OS X provides an integrated suite of object-oriented software components packagedin two core class libraries, the AppKit and Foundation frameworks, and a number of underlying frameworksproviding supporting technologies. Cocoa classes are reusable and extensible—you can use them as is orextend them for your particular requirements.

Cocoa provides program infrastructure to make the creation of applications easy. The extent of thisinfrastructure is such that you can create a new Cocoa application project in Xcode and without adding anycode have a functional application. Such an application is able to display its window (or create new documents)and implements many standard system behaviors. And although the Xcode templates provide some codeto make this all happen, the amount of code they provide is minimal. Most of the actual runtime behavioris provided by Cocoa itself.

To make your application fully functional, you need to understand the Cocoa infrastructure and know whatit expects you to provide. There are many ways to define a Cocoa application, so it is best to understandthese basics before you start your implementation. Otherwise, fixing your design later could be much harder.

Fundamental Design Patterns

Cocoa incorporates many specific design patterns in its implementation. You need to understand and usethese design patterns to write Cocoa applications successfully. Table 2-1 lists the key design patterns withwhich you should be familiar.

Table 2-1 Fundamental design patterns used by Mac OS X applications

Why it is importantDesign pattern

Use of the Model-View-Controller (MVC) design pattern ensures that the objectsyou create now can be reused or updated easily in future versions of yourapplication.

Cocoa framework provides most of the classes used to build your application’scontroller and view layers. It is your job to customize the classes you need andprovide the necessary data model objects to go with them.

Model-View-Controller

The delegation design pattern allows you to change the runtime behavior of anobject without subclassing. Delegate objects conform to a specific protocol thatdefines the interaction points between the delegate and the object it modifies.At specific points, the master object calls the methods of its delegate to provideit with information or ask what to do. The delegate can then take whatever actionsare appropriate.

Delegation

Fundamental Design Patterns 232011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 24: MOSXAppProgrammingGuide

Why it is importantDesign pattern

The responder chain defines the relationships between event-handling objectsin your application. As events arrive, the application dispatches them to the firstresponder object for handling. If that object does not want the event, it passes itto the next responder, which can either handle the event or send it to its nextresponder, and so on up the chain.

Windows and views are the most common types of responder objects and arealways the first responders for mouse events. Other types of objects, such as yourapplication’s controller objects, may also be responders.

Responder chain

Controls use the target-action design pattern to notify your application of userinteractions. When the user interacts with a control in a predefined way (such asby touching a button), the control sends a message (the action) to an object youspecify (the target). Upon receiving the action message, the target object can thenrespond in an appropriate manner.

Target-action

The garbage-collected memory model eliminates the need to retain and releaseobjects and memory explicitly.

For more information about the garbage collection system, see GarbageCollectionProgramming Guide.

Garbage-collectedmemory

Block objects are a convenient way to encapsulate code and local stack variablesin a form that can be executed later. Blocks are used in lieu of callback functionsby many frameworks and are also used in conjunction with Grand Central Dispatchto perform tasks asynchronously.

For more information about using blocks, see Blocks Programming Topics.

Block objects

Notifications are used throughout Cocoa to deliver news of changes to yourapplication. Many objects send notifications at key moments in the object’s lifecycle. Intercepting these notifications gives you a chance to respond and addcustom behavior.

Notifications

KVO tracks changes to a specific property of an object. When that propertychanges, the change generates automatic notifications for any objects thatregistered an interest in that property. Those observers then have a chance torespond to the change.

Key-Value Observing(KVO)

Cocoa bindings provide a convenient bridge between the model, view, andcontroller portions of your application. You bind a view to some underlying dataobject (which can be static or dynamic) through one of your controllers. Changesto the view are then automatically reflected in the data object, and vice versa.

The use of bindings is not required for applications but does minimize the amountof code you have to write. You can set up bindings programmatically or usingInterface Builder.

Bindings

For a more detailed discussion of Cocoa and the design patterns you use to implement Mac OS X applications,see Cocoa Fundamentals Guide.

24 Fundamental Design Patterns2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 25: MOSXAppProgrammingGuide

The Application Style Determines the Core Architecture

The style of your application defines which core objects you must use in its implementation. Cocoa supportsthe creation of both single-window and multiwindow applications. For multiwindow designs, it also providesa document architecture to help manage the files associated with each application window. Thus, applicationscan have the following forms:

● Single-window utility application

● Single-window “shoebox” application

● Multiwindow document application

You should choose a basic application style early in your design process because that choice affects everythingyou do later. The single-window styles are preferred in many cases, especially for developers bringingapplications over from iOS. The single-window style typically yields a more streamlined user experience, andit also makes it easier for your application to support a full-screen mode. However, if your application worksextensively with complex documents, the multiwindow style may be preferable because it provides moredocument-related infrastructure to help you implement your application.

The Calculator application provided with Mac OS X, shown in Figure 2-1, is an example of a single-windowutility application. Utility applications typically handle ephemeral data or manage system processes. Calculatordoes not create or deal with any documents or persistent user data but simply processes numerical dataentered by the user into the text field in its single window, displaying the results of its calculations in thesame field. When the user quits the application, the data it processed is simply discarded.

Figure 2-1 The Calculator single-window utility application

Single-window “shoebox” applications do handle persistent user data. One of the most prominent examplesof a shoebox application is iPhoto, shown in Figure 2-2. The user data handled by iPhoto are photos (andassociated metadata), which the application edits, displays, and stores. All user interaction with iPhotohappens in a single window. Although iPhoto stores its data in files, it doesn’t present the files to the user.The application presents a simplified interface so that users don’t need to manage files in order to use theapplication. Instead, they work directly with their photos. Moreover, iPhoto hides its files from regular

The Application Style Determines the Core Architecture 252011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 26: MOSXAppProgrammingGuide

manipulation in the Finder by placing them within a single package. In addition, the application saves theuser’s editing changes to disk at appropriate times. So, users are relieved of the need to manually save, open,or close documents. This simplicity for users is one of the key advantages of the shoebox application design.

Figure 2-2 The iPhoto single-window application

A good example of a multiwindow document application is TextEdit, which creates, displays, and editsdocuments containing plain or styled text and images. TextEdit does not organize or manage itsdocuments—users do that with the Finder. Each TextEdit document opens in its own window, multipledocuments can be open at one time, and the user interacts with the frontmost document using controls inthe window’s toolbar and the application’s menu bar. Figure 2-3 shows a document created by TextEdit.

26 The Application Style Determines the Core Architecture2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 27: MOSXAppProgrammingGuide

Figure 2-3 TextEdit document window

In Mac OS X v10.7, TextEdit implements automatic saving, an idea borrowed from the single-window design.Users no longer need to save their editing changes—the document architecture writes them to disk atappropriate times. Although users can manually save a version of the document if they wish, doing so isoptional. “Implementing a Document-Based Design” (page 49) explains how to create a multiwindow,document-based application.

The Core Objects for All Cocoa Applications

Regardless of whether you are using a single-window or multiwindow application style, all applications usethe same core set of objects. Cocoa provides the default behavior for most of these objects. However, youare expected to provide a certain amount of customization of these objects to implement your application’scustom behavior.

Figure 2-4 shows the relationships among the core objects for the single-window application styles. Theobjects in this figure are separated according to whether they are part of the model, view, or controllerportions of the application. As you can see from the figure, the Cocoa–provided objects provide much of thecontroller and view layer for your application.

The Application Style Determines the Core Architecture 272011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 28: MOSXAppProgrammingGuide

Figure 2-4 Key objects in a single-window application

Data Model ObjectsData Model ObjectsData Model Objects

Data Model ObjectsData Model ObjectsViews and UI ObjectsData Model ObjectsData Model ObjectsView controllers

(optional)

Model

Controller

EventLoop

View

NSWindow

NSApplication Application Delegate

Window Controller

Table 2-2 (page 28) describes the roles played by the objects in the diagram.

Table 2-2 The core objects used by all Cocoa applications

DescriptionObject

(Required) All applications have a single application object to run the event loop andmanage interactions between your application and the system. You typically use theNSApplication class as is, putting any custom application-object-related code in yourapplication delegate object.

NSApplicationobject

(Expected) The application delegate object is a custom object that you provide. It worksclosely with the NSApplication object to run the application and manage thetransitions between different application states.

Your application delegate object must conform to the NSApplicationDelegateProtocol.

Applicationdelegate object

Data model objects store your application’s content and are therefore specific to yourapplication. For example, a banking application might store a database containingfinancial transactions, whereas a painting application might store an image object oreven the sequence of drawing commands that led to the creation of that image. (In thelatter case, an image object is still a data object because it is just a container for theimage data. The actual rendering of that image still takes place elsewhere in yourapplication.)

Data modelobjects

28 The Application Style Determines the Core Architecture2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 29: MOSXAppProgrammingGuide

DescriptionObject

The NSWindowController class defines the base implementation for all windowcontroller objects. Each instance of this class is responsible for loading and managinga single window and coordinating with the system to handle standard window behaviors.

In your applications, you subclass NSWindowController to manage both the windowand its contents. Each window controller object is ultimately responsible for everythingthat happens in its window. If the contents of your window are simple, the windowcontroller object may do all of the management itself. If your window is more complex,the window controller might use one or more view controllers to manage portions ofthe window.

Windowcontrollers

You use instances of NSWindow as is to represent your onscreen windows. Windowobjects can be configured in different styles depending on your application’s needs.For example, most windows have title bars and borders but you can also configurewindows without those visual adornments.

Although not strictly required, a window object is almost always managed by acorresponding window controller.

Window objects

The NSViewController class defines the base implementation for all view controllerobjects. This class coordinates the loading of a single view hierarchy into your application.You can use view controllers to divide up the work for managing more sophisticatedwindow layouts. In such a scenario, your view controllers would work together (andwith the overarching window controller) to present the overall window contents.

If you have developed iOS applications, be aware that AppKit view controllers play aless prominent role than UIKit view controllers. In Mac OS X, AppKit view controllers areassistants to the window controller, which is ultimately responsible for everything thatgoes in the window. The main job of an AppKit view controller is to load its viewhierarchy. Everything else is custom code that you write.

View controllers

The NSView class defines the basic behavior for all views. A view defines a rectangularregion in a window, draws the contents of that region, and handles events in that region.Visually, views can be layered on top of each other to create view hierarchies, wherebyone view obscures a portion of the underlying view.

Cocoa provides several classes that represent the standard system controls. These classesprovide standard visual items such as buttons, text fields, and tables that you can useto build your user interface. Although a few views are used as is to present visualadornments, most work with your code to manage user interactions with yourapplication’s content.

View objects

Any application can also have secondary windows, also known as dialogs and panels. These windows aresubordinate to the current document window or, in the case of single-window applications, to the mainwindow. They support the document or main window in various ways—for example, allowing selection offonts and color, allowing the selection of tools from a palette, or displaying a warning‚ A secondary windowis often modal.

The Application Style Determines the Core Architecture 292011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 30: MOSXAppProgrammingGuide

Additional Core Objects for Multiwindow Applications

As opposed to a single-window application, a multiwindow application uses several windows to present itsprimary content. The Cocoa support for multiwindow applications is built around a document-based modelimplemented by a subsystem called the document architecture. In this model, each document object managesits content, coordinates the reading and writing of that content from disk, and presents the content in awindow for editing. All document objects work with the Cocoa infrastructure to coordinate event deliveryand such, but each document object is otherwise independent of its fellow document objects.

Figure 2-5 shows the relationships among the core objects of a multiwindow document-based application.Many of the same objects in this figure are identical to those used by a single-window application. The maindifference is the insertion of the NSDocumentController and NSDocument objects between the applicationobjects and the objects for managing the user interface.

Figure 2-5 Key objects in a multiwindow document application

Data Model Objects

NSWindowViews and UI Objects

View

Window controller

Model

Controller

EventLoop

NSApplication

NSDocument

View controllers (optional)

Application delegate

NSDocumentController

Table 2-3 (page 31) describes the role of the insertedNSDocumentController and NSDocument objects.(For information about the roles of the other objects in the diagram, see Table 2-2 (page 28).)

30 The Application Style Determines the Core Architecture2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 31: MOSXAppProgrammingGuide

Table 2-3 Additional objects used by multiwindow document applications

DescriptionObject

The NSDocumentController class defines a high-level controller for creating andmanaging all document objects. In addition to managing documents, the documentcontroller also manages many document-related menu items, such as the OpenRecent menu and the open and save panels.

Document Controllerobject

The NSDocument class is the base class for implementing documents in amultiwindow application. This class acts as the controller for the data objectsassociated with the document. You define your own custom subclasses to managethe interactions with your application’s data objects and to work with one or moreNSWindowController objects to display the document contents on the screen.

Document object

For more detailed information about multiwindow, document-based applications, see “Implementing aDocument-Based Design” (page 49).

Shoebox Applications Should Not Use NSDocument

When implementing a single-window, shoebox application, it is better not to use NSDocument objects tomanage your content. The NSDocument class was designed specifically for use in multiwindow documentapplications. Instead, use custom controller objects to manage your data. Those custom controllers wouldthen work with a view controller or your application’s main window controller to coordinate the presentationof the data.

Although you normally use an NSDocumentController object only in multiwindow applications, you cansubclass it and use it in a single-window application to coordinate the Open Recent and similar behaviors.When subclassing, though, you want to override any methods related to the creation of NSDocument objects.

The Application Life Cycle

The application life cycle is the progress of an application from its launch through its termination. Applicationscan be launched by either the user or the system. The user launches applications by double-clicking theapplication icon, using Launchpad, or by opening a file whose type is currently associated with the application.In Mac OS X v10.7 and later, the system launches applications at user login time when it needs to restore theuser’s desktop to its previous state.

When an application is launched, the system creates a process and all of the normal system-related datastructures for it. Inside the process, it creates a main thread and uses it to begin executing your application’scode. At that point, your application’s code takes over and your application is running.

The Application Life Cycle 312011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 32: MOSXAppProgrammingGuide

The main Function is the Application Entry Point

Like any C-based application, the main entry point for a Mac OS X application at launch time is the mainfunction. In a Mac OS X application, the main function is used only minimally. Its main job is to give controlto the AppKit framework. Therefore, any new project you create in Xcode comes with a default main functionlike the one shown in Listing 2-1. With few exceptions, you should never change the implementation of thisfunction.

Listing 2-1 The main function of a Mac OS X application

#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[]){ return NSApplicationMain(argc, (const char **) argv);}

The NSApplicationMain function initializes your application and prepares it to run. As part of the initializationprocess, this function does several things:

● The NSApplicationMain function creates an instance of the NSApplication class. You can accessthis object from anywhere in your application using the sharedApplication class method.

● It configures the memory management objects needed for the main thread.

● For garbage-collected applications, it installs a collector on the application’s main thread.

● For memory-managed applications, it installs a last-chance autorelease pool to catch autoreleasedobjects.

● It loads the nib file specified by the NSMainNibFile key in the Info.plist file and instantiates all ofthe objects in that file. This is your application’s main nib file and should contain your application delegateand any other critical objects that must be loaded early in the launch cycle. Any objects that are notneeded at launch time should be placed in separate nib files and loaded later.

● It calls the runmethod of your application object to finish the launch cycle and begin processing events.

By the time the run method is called, the main objects of your application are loaded into memory but theapplication is still not fully launched. The run method notifies the application delegate that the applicationis about to launch, shows the application menu bar, opens any any files that were passed to the application,does some framework housekeeping, and starts the event processing loop. All of this work occurs on theapplication’s main thread with one exception. Files may be opened in secondary threads if thecanConcurrentlyReadDocumentsOfType: class method of the corresponding NSDocument object returnsYES.

32 The Application Life Cycle2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 33: MOSXAppProgrammingGuide

Note: Although you can subclass NSApplication to customize the application behaviors, you should avoiddoing so whenever possible and use the default NSApplication class to run your application. If you dodecide to subclass, you must let Cocoa know that you have done so by setting the value of theNSPrincipalClass key to your custom class name in your application’s Info.plist file. TheNSApplicationMain function uses the value of that key when creating the application object. For moreabout your application’s Info.plist file, see “The Information Property List File” (page 80).

If your application preserves its user interface between launch cycles, Cocoa loads any preserved data atlaunch time and uses it to re-create the windows that were open the last time your application was running.For more information about how to preserve your application’s user interface, see “User InterfacePreservation” (page 37).

The Application’s Main Event Loop Drives Interactions

As the user interacts with your application, the application’s main event loop processes incoming events anddispatches them to the appropriate objects for handling. When the NSApplication object is first created,it establishes a connection with the system window server, which receives events from the underlyinghardware and transfers them to the application. The application also sets up a FIFO event queue to store theevents sent to it by the window server. The main event loop is then responsible for dequeueing and processingevents waiting in the queue, as shown in Figure 2-6.

Figure 2-6 The main event loop

Main run loop

Event sourceevent

event

eventeventevent

Window ServerMach Port

Observer

The run method of the NSApplication object is the workhorse of the main event loop. In a closed loop,this method executes the following steps until the application terminates:

1. The run method services window-update notifications, which results in the redrawing of any windowsthat are marked as “dirty.”

2. It dequeues an event from its internal event queue using thenextEventMatchingMask:untilDate:inMode:dequeue:method and converts the event data intoan NSEvent object.

3. It dispatches the event to the appropriate target object using the sendEvent: method ofNSApplication.

The Application Life Cycle 332011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 34: MOSXAppProgrammingGuide

The nextEventMatchingMask:untilDate:inMode:dequeue: method is the funnel point for the mainevent loop. If there are no events in the event queue, this method blocks the main thread. During that time,the window server is still processing events and may place new ones on the event queue. When that happens,the system wakes up the application’s main thread so that it can process the newly received events.

When the application dispatches an event, the sendEvent:method uses the type of the event to determinethe appropriate target. There are two major types of input events: key events and mouse events. Key eventsare sent to the key window—the window that is currently accepting key presses. Mouse events are dispatchedto the window in which the event occurred.

For mouse events, the window looks for the view in which the event occurred and dispatches the event tothat object first. Views are responder objects and are capable of responding to any type of event. If the viewis a control, it typically uses the event to generate an action message for its associated target. Other typesof views may process the events directly, use them to generate notifications or send messages to your code,pass them to other objects for handling, or ignore them entirely.

The overall process for handling events is described in detail in Cocoa Event-Handling Guide.

Automatic and Sudden Termination of Applications Improve theUser Experience

In Mac OS X v10.7 and later, the use of the Quit command to terminate an application is diminished in favorof more user-centric techniques. Specifically, Cocoa supports two techniques that make the termination ofan application transparent and fast:

● Automatic termination eliminates the need for users to quit an application. Instead, the system managesapplication termination transparently behind the scenes, terminating applications that are not in use toreclaim needed resources such as memory.

● Sudden termination allows the system to kill an application’s process immediately without waiting forit to perform any final actions. The system uses this technique to improve the speed of operations suchas logging out of, restarting, or shutting down the computer.

Automatic termination and sudden termination are independent techniques, although both are designedto improve the user experience of application termination. Although Apple recommends that applicationssupport both, an application can support one technique and not the other. Applications that support bothtechniques can be terminated by the system without the application being involved at all. On the other hand,if an application supports sudden termination but not automatic termination, then it must be sent a Quitevent, which it needs to process without displaying any user interface dialogs.

Automatic termination transfers the job of managing processes from the user to the system, which is betterequipped to handle the job. Users do not need to manage processes manually anyway. All they really needis to run applications and have those applications available when they need them. Automatic terminationmakes that possible while ensuring that system performance is not adversely affected.

Applications must opt in to both automatic termination and sudden termination and implement appropriatesupport for them. In both cases, the application must ensure that any user data is saved well before terminationcan happen. And because the user does not quit an autoterminable application, such an application shouldalso save the state of its user interface using the built-in Cocoa support. Saving and restoring the interfacestate provides the user with a sense of continuity between application launches.

34 The Application Life Cycle2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 35: MOSXAppProgrammingGuide

Note: If you do not opt in to automatic termination for your applications, the user must explicitly quit yourapplication to remove it from memory.

For information on how to support for automatic termination in your application, see “AutomaticTermination” (page 35). For information on how to support sudden termination, see “SuddenTermination” (page 36).

Support the Key Runtime Behaviors in Your Applications

No matter what style of application you are creating, there are specific behaviors that all applications shouldsupport. These behaviors are intended to help users focus on the content they are creating rather than focuson application management and other busy work that is not part of creating their content.

Automatic Termination

Automatic termination is a feature that you must explicitly code for in your application. Declaring supportfor automatic termination is easy, but applications also need to work with the system to save the currentstate of their user interface so that it can be restored later as needed. The system can “quit” an auto-terminableapplication at any time, so saving this information maintains continuity for the application. Usually, the systemquits the application some time after the user has closed all of its windows. However, the system may alsoquit an application with open windows if the application is not currently on screen, perhaps because theuser hid it or switched spaces.

Thus, to support automatic termination, you should do the following:

● Declare your application’s support for automatic termination, either programmatically or using anInfo.plist key; see “Enabling Automatic Termination in Your Application” (page 35).

● Support saving and restoring your window configurations; see “User Interface Preservation” (page 37).

● Save the user’s data at appropriate times.

● Single-window applications should implement strategies for saving data at appropriate checkpoints;see “Data-Saving Strategies for Single-Window Applications” (page 36).

● Multiwindow applications can use the autosaving and saveless documents capabilities in Cocoa;see “Implementing a Document-Based Design” (page 49).

● Whenever possible, support sudden termination for your application as well; see “SuddenTermination” (page 36).

Enabling Automatic Termination in Your Application

Declaring support for automatic termination lets the system know that it should manage the actual terminationof your application at appropriate times. An application has two ways to declare its support for automatictermination:

Support the Key Runtime Behaviors in Your Applications 352011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 36: MOSXAppProgrammingGuide

● Include the NSSupportsAutomaticTermination key (with the value YES) in the application’sInfo.plist file.

● Use the NSProcessInfo class to declare support for automatic termination dynamically. You can alsouse this class to change the default support of an application that includes theNSSupportsAutomaticTermination key in its Info.plist file.

Data-Saving Strategies for Single-Window Applications

When implementing a single-window application, avoid forcing the user to save changes manually. Instead,identify appropriate points in your code where any user-related changes should be saved and write thosechanges to disk automatically. This benefits the user by eliminating the need to think about manually savingchanges, and when done regularly, it ensures that the user does not lose much data if there is a problem.

Some appropriate times when you can save user data automatically include the following:

● When the user closes the application window or quits the application (applicationWillTerminate:)

● When the application is deactivated (applicationWillResignActive:)

● When the user hides your application (applicationWillHide:)

● Whenever the user makes a valid change to data in your application

The last item means that you have the freedom to save the user’s data at any time it makes sense to do so.For example, if the user is editing fields of a data record, you can save each field value as it is changed or youcan wait and save all fields when the user displays a new record. Making these types of incremental changesensures that the data is always up-to-date but also requires more fine-grained management of your datamodel. In such an instance, Core Data can help you make the changes more easily. For information aboutCore Data, see Core Data Starting Point.

Sudden Termination

Sudden termination lets the system know that your application’s process can be killed directly without anyadditional involvement from your application. The benefit of supporting sudden termination is that it letsthe system close applications more quickly, which is important when the user is shutting down a computeror logging out.

An application has two ways to declare its support for sudden termination:

● Include the NSSupportsSuddenTermination key (with the value YES) in the application’s Info.plistfile.

● Use the NSProcessInfo class to declare support for sudden termination dynamically. You can also usethis class to change the default support of an application that includes theNSSupportsSuddenTermination key in its Info.plist file.

36 Support the Key Runtime Behaviors in Your Applications2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 37: MOSXAppProgrammingGuide

One solution is to declare global support for the feature globally and then manually override the behaviorat appropriate times. Because sudden termination means the system can kill your application at any timeafter launch, you should disable it while performing actions that might lead to data corruption if interrupted.When the action is complete, reenable the feature again.

You disable and enable sudden termination programmatically using the disableSuddenTermination andenableSuddenTerminationmethods of theNSProcessInfo class. These methods increment and decrementa counter, respectively, maintained by the process. When the value of this counter is 0, the process is eligiblefor sudden termination. When the value is greater than 0, sudden termination is disabled.

Enabling and disabling sudden termination dynamically also means that your application should save dataprogressively and not rely solely on user actions to save important information. The best way to ensure thatyour application’s information is saved at appropriate times is to support the interfaces in Mac OS X v10.7for saving your document and window state. Those interfaces facilitate the automatic saving of relevant userand application data. For more information about saving your user interface state, see “User InterfacePreservation” (page 37). For more information about saving your documents, see “Implementing aDocument-Based Design” (page 49).

For additional information about enabling and disabling sudden termination, seeNSProcessInfoClass Reference.

User Interface Preservation

The Resume feature of Mac OS X v10.7 saves the state of your application’s windows and restores themduring subsequent launches of your application. Saving the state of your windows enables you to returnyour application to the state it was in when the user last used it. Use the Resume feature especially if yourapplication supports automatic application termination, which can cause your application to be terminatedwhile it is running but hidden from the user. If your application supports automatic termination but doesnot preserve its interface, the application launches into its default state. Users who only switched away fromyour application might think that the application crashed while it was not being used.

Writing Out the State of Your Windows and Custom Objects

The following sections primarily describe the process for preserving the state of a single-window application.However, most of the steps described in these sections also apply to multiwindow document applications.For additional information on what you need to do to save state in a multiwindow document-based application,see “Windows Are Restored Automatically” (page 65).

You must do the following to preserve the state of your user interface:

● For each window, you must set whether the window should be preserved using the setRestorable:method.

● For each preserved window, you must specify an object whose job is to re-create that window at launchtime.

● Any objects involved in your user interface must write out the data they require to restore their statelater.

● At launch time, you must use the provided data to restore your objects to their previous state.

Support the Key Runtime Behaviors in Your Applications 372011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 38: MOSXAppProgrammingGuide

The actual process of writing out your application state to disk and restoring it later is handled by Cocoa, butyou must tell Cocoa what to save. Your application’s windows are the starting point for all save operations.Cocoa iterates over all of your application’s windows and saves data for the ones whose isRestorablemethod returns YES. Most windows are preserved by default, but you can change the preservation state ofa window using the setRestorable: method.

In addition to preserving your windows, Cocoa saves data for most of the responder objects associated withthe window. Specifically, it saves the views and window controller objects associated with the window. (Fora multiwindow document-based application, the window controller also saves data from its associateddocument object.) Figure 2-7 shows the path that Cocoa takes when determining which objects to save.Window objects are always the starting point, but other related objects are saved, too.

Figure 2-7 Responder objects targeted by Cocoa for preservation

ViewViewViews

NSWindowController

NSDocument

Archived state

NSWindowNSWindowNSWindow

Although the Cocoa responder objects save a lot of useful information about the state of your windows andviews, they do not have any inherent knowledge about your application’s data structures. Therefore, it isyour responsibility to save any additional information needed to restore the window to its current state.There are several places where you can write out your custom state information:

● If you subclass NSWindow or NSView, implement the encodeRestorableStateWithCoder: methodin your subclass and use it to write out any relevant data.

Alternatively, your custom responder objects can override the restorableStateKeyPaths methodand use it to specify key paths for any attributes to be preserved. Cocoa uses the key paths to locate andsave the data for the corresponding attribute. Attributes must be compliant with key-value coding andkey-value observing.

● If your window has a delegate object, implement the window:willEncodeRestorableState:methodfor the delegate and use it to store any relevant data.

● In your window controller, use the encodeRestorableStateWithCoder:method to save any relevantdata or configuration information.

38 Support the Key Runtime Behaviors in Your Applications2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 39: MOSXAppProgrammingGuide

Be judicious when deciding what data to preserve, and strive to write out the smallest amount of informationthat is required to reconfigure your window and associated objects. All Cocoa window and view objects savebasic information about their size and location, plus information about other attributes that might affect theway they are currently displayed. For example, a tab view saves the index of the selected tab, and a text viewsaves the location and range of the current text selection. Those objects do not, however, save the actualdata they are displaying. You are expected to save enough information during the save process to reattachthe window to the same data objects later.

Important: Never use the user interface preservation mechanism as a way to save your application’s actualdata. The archive created for interface preservation can change frequently and may be ignored altogetherif there is a problem during the restoration process. Your application data should always be savedindependently in data files that are managed by your application.

For information on how to use coder objects to archive state information, see Archives and SerializationsProgramming Guide.

Notifying Cocoa About Changes to Your Interface State

Whenever the preserved state of one of your responder objects changes, mark the object as dirty by callingthe invalidateRestorableState method of that object. Having done so, at some point in the future,encodeRestorableStateWithCoder: message is sent to your responder object. Marking your responderobjects as dirty lets Cocoa know that it needs to write their preservation state to disk at an appropriate time.Invalidating your objects is a lightweight operation in itself because the data is not written to disk right away.Instead, changes are coalesced and written at key times, such as when the user switches to another applicationor logs out.

You should mark a responder object as dirty only for changes that are truly interface related. For example,a tab view marks itself as dirty when the user selects a different tab. However, you do not need to invalidateyour window or its views for many content-related changes, unless the content changes themselves causedthe window to be associated with a completely different set of data-providing objects.

If you used the restorableStateKeyPaths method to declare the attributes you want to preserve, Cocoapreserves and restores the values of those attributes of your responder object. Therefore, any key paths youprovide should be key-value observing compliant and generate the appropriate notifications. For moreinformation on how to support key-value observing in your objects, see Key-Value Observing ProgrammingGuide.

Restoring Your Windows and Custom Objects at Launch TIme

As part of your application’s normal launch cycle, Cocoa checks to see whether there is any preserved interfacedata. If there is, Cocoa uses that data to try to re-create your application’s windows. Of course, Cocoa doesneed help from your application to do that. Every window is expected to identify a class that knows aboutthe window and can act on its behalf at launch time. This class is known as the restoration class of thewindow and its job is to do whatever is necessary to create the window when asked to do so by Cocoa.

The restoration class is responsible for creating both the window and all of the critical objects required bythat window. For most application styles, the restoration class usually creates one or more controller objectsas well. For example, in a single-window application, the restoration class would likely create the windowcontroller used to manage the window and then retrieve the window from that object. Because it creates

Support the Key Runtime Behaviors in Your Applications 392011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 40: MOSXAppProgrammingGuide

these controller objects too, you typically use high-level application classes for your restoration classes. Anapplication might use the application delegate, a document controller, or even a window controller as arestoration class.

During the launch cycle, Cocoa does the following to create each preserved window:

1. Cocoa retrieves the window’s restoration class from the preserved data and calls itsrestoreWindowWithIdentifier:state:completionHandler: class method.

2. The restoreWindowWithIdentifier:state:completionHandler: class method is expected tocall the provided completion handler with the desired window object. To do this, it typically does oneof the following:

● It creates any relevant controller objects (including the window controller) that might normally becreated to display the window.

● If the controller objects already exist (perhaps because they were already loaded from a nib file),the method gets the window from those existing objects.

If the window could not be created, perhaps because the associated document was deleted by the user,the restoreWindowWithIdentifier:state:completionHandler: should pass an error object tothe completion handler.

3. Cocoa uses the returned window to restore it and any preserved responder objects to their previousstate.

● Standard Cocoa window and view objects are restored to their previous state without additionalhelp. If you subclass NSWindow or NSView, implement the restoreStateWithCoder: method torestore any custom state.

If you implemented the restorableStateKeyPaths method in your custom responder objects,Cocoa automatically sets the value of the associated attributes to their preserved values. Thus, youdo not have to implement the restoreStateWithCoder: to restore these attributes.

● For the window delegate object, Cocoa calls the window:didDecodeRestorableState: methodto restore the state of that object.

● For your window controller, Cocoa calls the restoreStateWithCoder:method to restore its state.

When re-creating each window, Cocoa passes the window’s unique identifier string to the restoration class.You are responsible for assigning identifier strings to your windows prior to preserving the window state.Your restoration class can use these identifiers to determine which window and associated objects it needsto re-create. The contents of an identifier string can be anything you want but should be something to helpyou identify the window later. For example, you might assign the string “preferences” as the unique identifierof your application’s preferences window.

For a single-window application whose main window controller and window are loaded from the main nibfile, the job of your restoration class is fairly straightforward. Here, you could use the application delegate’sclass as the restoration class and implement therestoreWindowWithIdentifier:state:completionHandler: method similar to the implementationshown in Listing 2-2. Because the application has only one window, it returns the main window directly. Ifyou used the app delegate’s class as the restoration class for other windows, your own implementation coulduse the identifier parameter to determine which window to create.

40 Support the Key Runtime Behaviors in Your Applications2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 41: MOSXAppProgrammingGuide

Listing 2-2 Returning the main window for a single-window application

+ (void)restoreWindowWithIdentifier:(NSString *)identifier state:(NSCoder *)state completionHandler:(void (^)(NSWindow *, NSError *))completionHandler{ // Get the window from the window controller, // which is stored as an outlet by the delegate. // Both the app delegate and window controller are // created when the main nib file is loaded. MyAppDelegate* appDelegate = (MyAppDelegate*)[[NSApplication sharedApplication] delegate]; NSWindow* mainWindow = [appDelegate.windowController window];

// Pass the window to the provided completion handler. completionHandler(mainWindow, nil);}

Using Custom Restoration Code to Preserve Your Interface

If your application already preserves its state and restores it upon subsequent relaunches, you should stillincorporate support for the Cocoa restoration process. Cocoa stores information besides just your windowinformation when saving your user interface. It later uses this information to drop your new window objectsinto the places where other parts of the system might be expecting the old window objects. So it is importantto allow this to happen.

When it comes time to restore your windows, plan to use a restoration class to initiate the restore process.You do not need to encode and restore the state of your interface objects using the Cocoa-provided methodsif you already have your own code to do that, but you do need to provide Cocoa with the new window objectyou restored yourself. Thus, the restoreWindowWithIdentifier:state:completionHandler:methodof your restoration class would typically just return a window that you already created and restored withyour custom code. Listing 2-3 shows a possible implementation for this method that retrieves an alreadycreated window from elsewhere in your application.

Listing 2-3 Providing Cocoa with an already restored window

+ (void)restoreWindowWithIdentifier:(NSString *)identifier state:(NSCoder *)state completionHandler:(void (^)(NSWindow *, NSError *))completionHandler{ // Get the window that has already been restored. NSWindow *window = getMyAlreadyRestoredWindow();

// Pass the window to the provided completion handler. completionHandler(window, nil);}

Cocoa triggers the restoration of your windows between calls to the applicationWillFinishLaunching:and applicationDidFinishLaunching: methods of your application delegate. This timing gives yourapplication delegate an opportunity to create and restore its windows in theapplicationWillFinishLaunching: method and be able to provide those windows to Cocoa later. IfCocoa asks for a window that (for whatever reason) you cannot restore or do not want to restore, pass nilfor the window when calling the completion handler.

Support the Key Runtime Behaviors in Your Applications 412011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 42: MOSXAppProgrammingGuide

Tweaking the Restoration Process in Your Application Object

The NSApplication object starts the interface restoration process and handles any problems that mightarise. You should not need to modify the default application behavior for this process in most cases, but ifyou find that you need to make adjustments, you can override the application object’srestoreWindowWithIdentifier:state:completionHandler: method to do so.

The restoreWindowWithIdentifier:state:completionHandler: method is the application’s funnelpoint for creating windows. The default behavior of this method is to get the restoration class for the windowand use that class to obtain the corresponding window object. However, if you remove a class from yourapplication that was acting as a restoration class, you can override this method to detect that case and providea new restoration class.

For more information about overriding this method, see NSApplication Class Reference.

Applications Are Built Using Many Different Pieces

The objects of the core architecture are important but are not the only objects you need to consider in yourdesign. The core objects manage the high-level behavior of your , but the objects in your application’s viewlayer do most of the work to display your custom content and respond to events. Other objects also playimportant roles in creating interesting and engaging applications.

The User Interface

An application’s user interface is made up of a menu bar, one or more windows, and one or more views. Themenu bar is a repository for commands that the user can perform in the application. Commands may applyto the application as a whole, to the currently active window, or to the currently selected object. You areresponsible for defining the commands that your application supports and for providing the event-handlingcode to respond to them.

You use windows and views to present your application’s visual content on the screen and to manage theimmediate interactions with that content. A window is an instance of the NSWindow class. A panel is aninstance of the NSPanel class (which is a descendant of NSWindow) that you use to present secondarycontent. Single-window applications have one main window and may have one or more secondary windowsor panels. Multiwindow applications have multiple windows for displaying their primary content and mayhave one or more secondary windows or panels too. The style of a window determines its appearance onthe screen. Figure 2-8 shows the menu bar, along with some standard windows and panels.

42 Applications Are Built Using Many Different Pieces2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 43: MOSXAppProgrammingGuide

Figure 2-8 Windows and menus in an application

Z-order

Menu barDockModal panels Restart alert Font panelApplication windows Untitled Untitled-1 Untitled-2

Levels

A view, an instance of the NSView class, defines the content for a rectangular region of a window. Views arethe primary mechanism for presenting content and interacting with the user and have several responsibilities.For example:

● Drawing and animation support. Views draw content in their rectangular area. Views that support CoreAnimation layers can use those layers to animate their contents.

● Layout and subview management. Each view manages a list of subviews, allowing you to create arbitraryview hierarchies. Each view defines layout and resizing behaviors to accommodate changes in the windowsize.

● Event handling. Views receive events. Views forward events to other objects when appropriate.

For information about creating and configuring windows, see Window Programming Guide. For informationabout using and creating view hierarchies, see View Programming Guide.

Event Handling

The system window server is responsible for tracking mouse, keyboard, and other events and delivering themto your application. When the system launches an application, it creates both a process and a single threadfor the application. This initial thread becomes the application’s main thread. In it, the NSApplicationobject sets up the main run loop and configures its event-handling code, as shown in Figure 2-9. As thewindow server delivers events, the application queues those events and then processes them sequentiallyin the application’s main run loop. Processing an event involves dispatching the event to the applicationobject best suited to handle it. For example, mouse events are usually dispatched to the view in which theevent occurred.

Applications Are Built Using Many Different Pieces 432011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 44: MOSXAppProgrammingGuide

Figure 2-9 Processing events in the main run loop

Operatingsystem

Event queue

Applicationobject

Application

Core objects

Note: A run loop monitors sources of input on a specific thread of execution. The application’s event queuerepresents one of these input sources. While the event queue is empty, the main thread sleeps. When anevent arrives, the run loop wakes up the thread and dispatches control to the NSApplication object tohandle the event. After the event has been handled, control passes back to the run loop, which can thenprocess another event, process other input sources, or put the thread back to sleep if there is nothing moreto do. For more information about how run loops and input sources work, see Threading ProgrammingGuide.

Distributing and handling events is the job of responder objects, which are instances of the NSResponderclass. TheNSApplication,NSWindow,NSDrawer,NSView,NSWindowController, andNSViewControllerclasses are all descendants of NSResponder. After pulling an event from the event queue, the applicationdispatches that event to the window object where it occurred. The window object, in turn, forwards theevent to its first responder. In the case of mouse events, the first responder is typically the view object(NSView) in which the touch took place. For example, a mouse event occurring in a button is delivered tothe corresponding button object.

If the first responder is unable to handle an event, it forwards the event to its next responder, which istypically a parent view, view controller, or window. If that object is unable to handle the event, it forwardsit to its next responder, and so , until the event is handled. This series of linked responder objects is knownas the responder chain. Messages continue traveling up the responder chain—toward higher-level responderobjects, such as a window controller or the application object—until the event is handled. If the event isn'thandled, it is discarded.

The responder object that handles an event often sets in motion a series of programmatic actions by theapplication. For example, a control object (that is, a subclass of NSControl) handles an event by sending anaction message to another object, typically the controller that manages the current set of active views. Whileprocessing the action message, the controller might change the user interface or adjust the position of viewsin ways that require some of those views to redraw themselves. When this happens, the view and graphicsinfrastructure takes over and processes the required redraw events in the most efficient manner possible.

For more information about responders, the responder chain, and handling events, see Cocoa Event-HandlingGuide.

44 Applications Are Built Using Many Different Pieces2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 45: MOSXAppProgrammingGuide

Graphics, Drawing, and Printing

There are two basic ways in which a Mac OS X application can draw its content:

● An application can use native drawing technologies (such as Core Graphics and AppKit).

● An application can use OpenGL.

The native Mac OS X drawing technologies typically use the infrastructure provided by Cocoa views andwindows to render and present custom content. When a view is first shown, the system asks it to draw itscontent. System views draw their contents automatically, but custom views must implement a drawRect:method. Inside this method, you use the native drawing technologies to draw shapes, text, images, gradients,or any other visual content you want. When you want to update your view’s visual content, you mark all orpart of the view invalid by calling its setNeedsDisplay: or setNeedsDisplayInRect: method. Thesystem then calls your view’s drawRect: method (at an appropriate time) to accommodate the update. Thiscycle then repeats and continues throughout the lifetime of your application.

If you are using OpenGL to draw your application’s content, you still create a window and view to manageyour content, but those objects simply provide the rendering surface for an OpenGL drawing context. Onceyou have that drawing context, your application is responsible for initiating drawing updates at appropriateintervals.

For information about how to draw custom content in your views, see Cocoa Drawing Guide.

Text Handling

The Cocoa text system, the primary text-handling system in Mac OS X, is responsible for the processing anddisplay of all visible text in Cocoa. It provides a complete set of high-quality typographical services throughthe text-related AppKit classes, which enable applications to create, edit, display, and store text with all thecharacteristics of fine typesetting.

The Cocoa text system provides all these basic and advanced text-handling features, and it also satisfiesadditional requirements from the ever-more-interconnected computing world: support for the character setsof all of the world’s living languages, powerful layout capabilities to handle various text directionality andnonrectangular text containers, and sophisticated typesetting capabilities such as control of kerning, ligatures,line breaking, and justification. Cocoa’s object-oriented text system is designed to provide all these capabilitieswithout requiring you to learn about or interact with more of the system than is necessary to meet the needsof your application.

Underlying the Cocoa text system is Core Text, which provides low-level, basic text layout and font-handlingcapabilities to higher-level engines such as Cocoa and WebKit. Core Text provides the implementation formany Cocoa text technologies. Application developers typically have no need to use Core Text directly.However, the Core Text API is accessible to developers who must use it directly, such as those writingapplications with their own layout engine and those porting older ATSUI- or QuickDraw-based codebasesto the modern world.

For more information about the Cocoa text system, see Cocoa Text Architecture Guide.

Applications Are Built Using Many Different Pieces 452011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 46: MOSXAppProgrammingGuide

Implementing the Application Menu Bar

The classes NSMenu and NSMenuItem are the basis for all types of menus. An instance of NSMenu managesa collection of menu items and draws them one beneath another. An instance of NSMenuItem represents amenu item; it encapsulates all the information its NSMenu object needs to draw and manage it, but does nodrawing or event-handling itself. You typically use Interface Builder to create and modify any type of menu,so often there is no need to write any code.

The application menu bar stretches across the top of the screen, replacing the menu bar of any otherapplication when the application is foremost. All of an application’s menus in the menu bar are owned byone NSMenu instance that’s created by the application when it starts up.

Xcode Templates Provide the Main Menu

Xcode’s Cocoa application templates provide that NSMenu instance in a nib file called MainMenu.xib. Thisnib file contains an application menu (named with the application’s name), a File menu (with all of itsassociated document commands), an Edit menu (with text editing commands and Undo and Redo menuitems), and Format, View, Window, and Help menus (with their own menu items representing commands).These menu items, as well as all of the menu items of the File menu, are connected to the appropriatefirst-responder action methods. For example, the About menu item is connected to theorderFrontStandardAboutPanel: action method that displays a standard About window.

The following table lists the File menu first-responder action connections that already exist in the templateapplication.

First-responder actionFile menu command

newDocument:New

openDocument:Open...

clearRecentDocuments:Open Recent > Clear Menu

performClose:Close

saveDocument:Save

saveDocumentAs:Save As...

revertDocumentToSaved:Revert to Saved

runPageLayout:Page Setup...

printDocument:Print...

The template has similar ready-made connections for the Edit, Format, View, Window, and Help menus. Ifyour application does not support any of the supplied actions (for example, printing), you should removethe associated menu items (or menu) from the nib. Alternatively, you may want to repurpose and renamemenu commands and action methods to suit your own application, taking advantage of the menu mechanismin the template to ensure that everything is in the right place.

46 Implementing the Application Menu Bar2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 47: MOSXAppProgrammingGuide

Connect Menu Items to Your Code or Your First Responder

For your application’s custom menu items that are not already connected to action methods in objects orplaceholder objects in the nib file, there are two common techniques for handling menu commands in aMac OS X application:

● Connect the corresponding menu item to a first responder method.

● Connect the menu item to a method of your custom application object or your application delegateobject.

Of these two techniques, the first is more common given that many menu commands act on the currentdocument or its contents, which are part of the responder chain. The second technique is used primarily tohandle commands that are global to the application, such as displaying preferences or creating a newdocument. It is possible for a custom application object or its delegate to dispatch events to documents, butdoing so is generally more cumbersome and prone to errors. In addition to implementing action methodsto respond to your menu commands, you must also implement the methods of the NSMenuValidationprotocol to enable the menu items for those commands.

Step-by-step instructions for connecting menu items to action methods in your code are given in “DesigningUser Interfaces in Xcode”. For more information about menu validation and other menu topics, see ApplicationMenu and Pop-up List Programming Topics.

Implementing the Application Menu Bar 472011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 48: MOSXAppProgrammingGuide

48 Implementing the Application Menu Bar2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 2

The Core Application Design

Page 49: MOSXAppProgrammingGuide

A multiwindow, document-based application is one of the more common types of applications. Documentsare identically contained but uniquely composed sets of data that can be stored in files. Traditional wordprocessors and spreadsheet applications are examples of document-based applications. One applicationtypically handles multiple documents, each in its own window, and often displays more than one documentat a time. Cocoa provides excellent support for this design through a subsystem called the documentarchitecture.

Three Key Objects Support Document-Based Applications

There are three major classes in the document architecture: NSDocumentController, NSDocument, andNSWindowController. Objects of these classes divide and orchestrate the work of creating, saving, opening,and managing the documents of an application. They are arranged in a tiered one-to-many relationship, asdepicted in Figure 3-1. An application can have only one NSDocumentController object, which createsand manages one or more NSDocument objects (one for each New or Open operation). In turn, an NSDocumentobject creates and manages one or more NSWindowController objects, one for each of the windowsdisplayed for a document. In addition, some of these objects have responsibilities analogous toNSApplication and NSWindow delegates, such as approving major events like closing and quitting.

These objects are also described in “The Core Objects for All Cocoa Applications” (page 27) and “AdditionalCore Objects for Multiwindow Applications” (page 30).

Three Key Objects Support Document-Based Applications 492011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 50: MOSXAppProgrammingGuide

Figure 3-1 Relationships among NSDocumentController, NSDocument, and NSWindowControllerobjects

Owns and manages

NSWindowController NSWindowController NSWindowController

NSDocument NSDocument

NSDocumentController

NSDocumentController Creates and Manages Documents

An application’s NSDocumentController object is a high-level controller. It has the following primaryresponsibilities:

● A document controller creates empty documents in response to the New item in the File menu

● It creates documents initialized with data from a file in response to the Open item in the File menu

● It tracks and manages those documents

● It handles document-related menu items, such as Open Recent

When a user chooses New from the File menu, the NSDocumentController object gets the appropriateNSDocument subclass from the application’s Information property list and allocates and initializes an instanceof this class. Likewise, when the user chooses Open, the NSDocumentController object displays the Openpanel, gets the user’s selection, finds the NSDocument subclass for the file, allocates an instance of the class,and initializes it with data from the file. In both cases, the NSDocumentController object adds a referenceto the document object to an internal list to help manage its documents.

50 Three Key Objects Support Document-Based Applications2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 51: MOSXAppProgrammingGuide

NSDocumentController is hard-wired to respond appropriately to certain application events, such as whenthe application starts up, when it terminates, when the system is shutting down, and when documents areopened or printed from the Finder. Most of the time, you can use this class as is to manage your application’sdocuments. Alternatively, you can make the application delegate a custom object and implement the delegatemethods invoked as a result of the same events, and these methods will be invoked instead (seeNSApplicationDelegate Protocol Reference).

Generally, the default NSDocumentController object is an adequate application controller for mostsituations. If the default object does not meet all of your requirements for an application controller—forexample, handling user preferences or responding to uncommon application delegate messages—usuallyyou should create a separate controller object (instead of subclassing NSDocumentController). However,it is possible to create a custom subclass to tweak your application’s document-handling behavior, as describedin “You Rarely Need to Subclass NSDocumentController” (page 58).

NSDocument Presents and Stores Document Data

NSDocument is the base class for document objects in the application architecture—you must create anNSDocument subclass for each type of document your application handles. When your application is running,it has an NSDocument-based object for each open document to manage the persistent data associated withthat document. As such, an NSDocument object is a model-controller with the following responsibilities:

● An NSDocument object manages the display and capture of the data in its windows (with the assistanceof its window controllers)

● It loads and stores (that is, reads and writes) the persistent data associated with its document

● It responds to action messages to save, print, revert, and close documents

● It runs and manages the Save and Page Setup dialogs

A fully implemented NSDocument object also knows how to track its edited status, perform undo and redooperations, print document data, and validate its menu items. Although these behaviors aren’t completelyprovided by default, the NSDocument object does assist the developer in implementing each, in the followingways:

● For tracking edited status, NSDocument provides an API for updating a change counter.

● For undo and redo operations, NSDocument lazily creates an NSUndoManager instance when one isrequested, responds appropriately to Undo and Redo menu commands, and updates the change counterwhen undo and redo operations are performed.

● For printing, NSDocument facilitates the display of the Page Setup dialog and the subsequent modificationof the NSPrintInfo object used in printing. To do this, subclasses of NSDocument must overrideprintOperationWithSettings:error:.

● To validate menu items, NSDocument implements validateUserInterfaceItem: to manage theenabled state of the Revert and Save As menu items. If you want to validate other menu items, you canoverride this method, but be sure to invoke the superclass implementation. For more information onmenu item validation, see NSUserInterfaceValidations Protocol Reference.

Three Key Objects Support Document-Based Applications 512011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 52: MOSXAppProgrammingGuide

When designing your document objects, you should always maintain a clean separation between thesedata-handling activities of the document object itself and the code for managing the visual presentation ofthat data. The document object is responsible for the data, including the reading and writing of that data todisk. The visual presentation of that data is the responsibility of the associated window controller object.Keeping a clean separation between these two activities makes for a more modular design that can beupdated more easily in the future.

Any and all objects that are part of the persistent state of a document should be considered part of thatdocument’s model. Sometimes the NSDocument object itself has some data that would be considered partof the model. For example, the Sketch example application has a subclass of NSDocument namedSKTDrawDocument; objects of this class might have an array of SKTGraphic objects that comprises themodel of the document. In addition to the actual SKTGraphic objects, the SKTDrawDocument object containssome data that should technically be considered part of the model, because the order of the graphics withinthe document’s array matters in determining the front-to-back ordering of the SKTGraphic objects.

An NSDocument object should not contain or require the presence of any objects that are specific to theapplication’s user interface. Although a document can own and manage NSWindowControllerobjects—which present the document visually and allow the user to edit it—it should not depend on theseobjects being there. For example, it might be desirable to have a document open in your application withouthaving it visually displayed.

For details about subclassing NSDocument, see “You Must Subclass NSDocument” (page 53).

If you have a large data set or require a managed object model, you may want to useNSPersistentDocument, a subclass of NSDocument, to create a document-based application that usesCore Data. For more information, see Core Data Starting Point.

NSWindowController Manages One Document Window

An NSWindowController object manages one window associated with a document, which is usually storedin a nib file. As such, it is a view-controller. If a document has multiple windows, each window has its ownwindow controller. For example, a document might have a main data-entry window and a window that listsrecords for selection; each window would have its own NSWindowController object. When requested byits owning NSDocument object, an NSWindowController object loads the nib file containing a window,displays the window, and sets itself as the File’s Owner of the nib file. It also assumes responsibility for closingwindows properly (after ensuring that the data they display is saved).

Window controllers keep track of their window using their window outlet. The window outlet of your windowcontroller (set as the File’s Owner in your nib file) should be connected to the window for which your windowcontroller is responsible.

While not required, it’s often convenient to set up your window controller as the delegate of the window itmanages. In your nib file, connect the delegate outlet of the window your window controller is managingto the object that represents your window controller—specifically, the File’s Owner object.

52 Three Key Objects Support Document-Based Applications2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 53: MOSXAppProgrammingGuide

Note: NSWindowController does not depend on being the controlled window's delegate to do its job,and it doesn't implement any NSWindow delegate methods. A subclass of NSWindowController, however,is a fine place to put implementations of NSWindow delegate methods, and if you do so you'll probably needto connect the delegate outlet of the window to the File's Owner of the nib file as described. But you do nothave to do so for NSWindowController itself to work properly.

The Xcode document-based application template does not subclass NSWindowController, and you do notneed to do so if you are writing a simple application. However, if you are writing an application with moreadvanced requirements, you will almost certainly want to do so. For more information, see “You May Wantto Subclass NSWindowController” (page 56).

Subclassing Objects in the Document Architecture

You can create a document-based application without writing much code. If your requirements are minimal,you can use the default NSWindowController instance and default NSDocumentController instanceprovided by the AppKit framework. You have only to create a document project, compose the human interface,implement a subclass of NSDocument, and add any other custom classes or behavior required by yourapplication. If your application requirements are more complex, you can customize the default objectarchitecture through subclassing and delegation, as described in this section.

Table 3-1 summarizes the object architecture and subclass requirements of a document-based application.

Table 3-1 Document Architecture Objects and Subclasses

SubclassingNumber of objectsClass

Required1 per documentNSDocument

Optional (but likely)1 per windowNSWindowController

Optional (but unlikely)1 per applicationNSDocumentController

You Must Subclass NSDocument

Every application that uses the document architecture must create at least one subclass of NSDocument. Tocreate a document-based Cocoa application, you choose the Xcode template presented in the New Projectdialog. When you do this, you get a new application project that already contains a subclass of NSDocumentand nib files for your document and application menu. Empty method implementations are provided forloading and saving data; comments explain what you need to fill in. Empty methods are also provided fordocument initialization, specifying the window nib file name, and adding code that is called after the documentnib file is loaded.

Without writing any additional code, you should be able to compile and run the application. When you firstlaunch the application, you see an untitled document with an empty window. The File menu commands alldo something reasonable, such as bringing up a Save panel or Open panel. Because you have not yet definedany types or implemented loading and saving, you can't open or save anything.

Subclassing Objects in the Document Architecture 532011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 54: MOSXAppProgrammingGuide

Subclass only NSDocument for documents that have only one window and are simple enough that thereisn’t much benefit in splitting the controller layer into a model-controller and a view-controller. TheNSDocument subclass provides storage for the model and the ability to load and save document data. It alsohas any outlets and actions required for the user interface. It overrides the windowNibNamemethod to returnthe nib file name used for documents of this type. The NSDocument object automatically creates anNSWindowController object to manage that nib file, but the NSDocument object serves as the File’s Ownerproxy object for the nib file.

The document architecture requires that you override some NSDocument methods (among several choices),and recommends overriding several others in certain situations. You must override one reading and onewriting method. In the simplest case, you can override the two data-based reading and writing methods. Ifyou need to deal with the location of the file, then you can override the URL-based reading and writingmethods instead.

If your application supports document files that are file packages, then you can override the file-wrapperreading and writing methods instead. Note that these methods read and write entire files at once. If yourapplication has a large data set, you may want instead to read and write pieces of your files at different times.For information about reading and writing files, see File System Programming Guide.

Initializing a New Document

The initializers of NSDocument are an issue for subclasses. The init method is the designated initializer, andit is invoked by the other initializers initWithType:error: andinitWithContentsOfURL:ofType:error:. If you must perform initializations that must be done whencreating new documents but not when opening existing documents, override initWithType:error:. Ifyou have any initializations that apply only to documents that are opened, overrideinitWithContentsOfURL:ofType:error:. If you have general initializations, override init. In all threecases, be sure to invoke the superclass implementation as the first thing.

If you override init, make sure that your override never returns nil. Returning nil could cause a crash (insome versions of AppKit) or present a less than useful error message. If, for example, you want to preventthe creation or opening of documents under circumstances unique to your application, override a specificNSDocumentController method instead.

Note: If you don’t want to open an untitled file when the application is launched or activated, implementthe application delegate method applicationShouldOpenUntitledFile: to return NO. If you do wantto open an untitled file when launched, but don't want to open an untitled file when already running andactivated from the dock, you can instead implement the delegate’sapplicationShouldHandleReopen:hasVisibleWindows: method to return NO.

Reading Document Data

Typically, document-based applications need to override one of the following methods to read documentdata:

● readFromData:ofType:error:

● readFromURL:ofType:error:

● readFromFileWrapper:ofType:error:

54 Subclassing Objects in the Document Architecture2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 55: MOSXAppProgrammingGuide

The readFromData:ofType:error: method may be overridden to convert an NSData object containingdocument data of a certain type into the document’s internal data structures and display that data in adocument window. The NSData object usually results from the document reading a document file.

The readFromURL:ofType:error:method reads data from a file, creates an NSFileWrapper object fromit, and gives this object to the readFromFileWrapper:ofType:error: method. If this object representsa simple file, it is passed to the readFromData:ofType:error: method for processing; otherwise (if theobject represents a directory), the readFromFileWrapper:ofType:error: method can be overridden tohandle the situation. Subclasses can override any of these methods instead of the data-based reading methodsif the way NSDocument reads and writes document data is not sufficient; their override implementations,however, must also assume the loading duties of the data-based reading methods.

Concurrent Document Opening

A class method of NSDocument, canConcurrentlyReadDocumentsOfType:, enables your NSDocumentsubclass to load documents concurrently, using background threads. You can override this method to returnYES to enable this capability. When you do, initWithContentsOfURL:ofType:error: executes on abackground thread when opening files via the Open panel or from the Finder. This override allows concurrentreading of multiple documents and also allows the application to be responsive while reading a largedocument.

The default implementation of this method returns NO. A subclass override should return YES only fordocument types whose reading code can be safely executed concurrently, in non-main threads. If a documenttype relies on shared state information, you should return NO for that type. Also, you should disable undoregistration during document reading, which is a good idea even in the absence of concurrency.

Saving Document Data

Typically, document-based applications need to override one of the following methods to write documentdata:

● dataOfType:error:

● writeToURL:ofType:error:

● fileWrapperOfType:error:

● writeToURL:ofType:forSaveOperation:originalContentsURL:error:

The dataOfType:error: method may be overridden to create and return document data (packaged as anNSData object) of a supported type, usually in preparation for writing that data to a file. By default, thewriteToURL:ofType:error: method writes data to a file after obtaining the data from thefileWrapperOfType:error: method, which gets it from the dataOfType:error: method.

You can override thewriteToURL:ofType:forSaveOperation:originalContentsURL:error:methodinstead of one of the other three, simple writing methods if your document writing machinery needs accessto the on-disk representation of the document revision that is about to be overwritten. This method isresponsible for doing document writing in a way that minimizes the danger of leaving the disk to whichwriting is being done in an inconsistent state in the event of an application crash, system crash, hardwarefailure, power outage, and so on.

Subclassing Objects in the Document Architecture 552011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 56: MOSXAppProgrammingGuide

By default, when NSDocument runs the Save panel and the document has multiple writable document types,NSDocument inserts an accessory view near the bottom of the panel. This view contains a pop-up menu ofthe writable types. If you don’t want this pop-up menu, override shouldRunSavePanelWithAccessoryViewto return NO. You can also override prepareSavePanel: to customize of the Save panel.

Warning: If your NSDocument subclass uses an NSTextView object to display its data and it has anactive NSUndoManager object, your document-writing method override (or another override calledduring document saving) should send the NSTextView object a breakUndoCoalescing message.Send this message when saving the text view’s contents to preserve proper tracking of unsaved changesand the document’s dirty state. See “Implementing Undo” (page 61) for more information aboutsupporting undo.

You can define types for your application using the Xcode Property List editor, which provides an editablelist of document types as described in “Supported Document Types Are Declared in the Application PropertyList” (page 59).

You May Want to Subclass NSWindowController

If your document has only one window but it is complex enough that you’d like to split up some of the logicin the controller layer, you can subclass NSWindowController as well as NSDocument. In this way, you canadd specific knowledge of the application’s view layer that the window controller is responsible for managing.Any outlets and actions and any other behavior that is specific to the management of the user interface goesinto the NSWindowController subclass. Especially for larger applications, splitting the controller dutiesbetween two classes makes a lot of sense. This strategy allows you to have documents that are open, butnot onscreen, to avoid having to allocate memory and other resources of a front end that may not be usedin some circumstances.

Reasons to Subclass NSWindowController

If your document requires or allows multiple windows for a single document, that is a good reason to subclassNSWindowController. For example, a CAD program could need to present front, top, and side views, aswell as a rendered 3D view of a document. When it does, you might want to have one or more subclassesof NSWindowController to manage the different kinds of windows that your document needs, and so youmust create one of each in makeWindowControllers.

Some applications need only one window for a document but want to allow the user to create several copiesof the window for a single document (sometimes this is called a multiple-view document) so that the usercan have each window scrolled to a different position or displayed differently, such as at a different scale. Inthis case, your makeWindowControllers override may create only one NSWindowController object, butwould have be a menu command or similar control that allows the user to create others.

Another reason to subclass NSWindowController is to customize your document window titles. To customizea document's window title properly, subclass NSWindowController and overridewindowTitleForDocumentDisplayName:. If your application requires even deeper customization, overridesynchronizeWindowTitleWithDocumentName.

56 Subclassing Objects in the Document Architecture2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 57: MOSXAppProgrammingGuide

How to Subclass NSWindowController

Once you've decided to subclass NSWindowController, you need to change the default document-basedapplication setup. First, add any Interface Builder outlets and actions for your document's user interface tothe NSWindowController subclass instead of to the NSDocument subclass. The NSWindowControllersubclass instance should be the File’s Owner for the nib file because that creates better separation betweenthe view-related logic and the model-related logic. Some menu actions can still be implemented in theNSDocument subclass. For example, Save and Revert are implemented by NSDocument, and you might addother menu actions of your own such as an action for creating new views on a document.

Second, instead of overriding windowNibName in your NSDocument subclass, overridemakeWindowControllers. In makeWindowControllers, create at least one instance of your customNSWindowController subclass and use addWindowController: to add it to the document. If yourdocument always needs multiple controllers, create them all here. If your document will support multipleviews but by default has one, create the controller for the default view here and provide user actions forcreating other views.

You should not force the windows to be visible in makeWindowControllers. NSDocument does that foryou if it’s appropriate.

An NSWindowController Subclass Manages Nib Files

An NSWindowController object expects to be told what nib file to load (through itsinitWithWindowNib... methods), because it is a generic implementation of the default behavior for allwindow controllers. However, when you write a subclass of NSWindowController, that subclass is almostalways designed to control the user interface contained in a particular nib file, and your subclass would notwork with a different nib file. It is therefore inconvenient and error-prone for the client of the subclass tohave to tell it which nib file to load.

This is solved by overriding the init method to call the superclass's initWithWindowNibName: methodwith the correct nib name. Now, clients just use init, and the controller has the correct nib file. You can alsooverride the initWithWindowNib... methods to log an error, because no clients should ever try to tellyour subclass which nib file to use. This is a good idea for any NSWindowController subclass designed towork with a specific nib file. You should do otherwise only if you are extending only the basic functionalityof NSWindowController in your subclass and have not tied that functionality to any particular nib file.

An NSWindowController object without an associated NSDocument object is useful by itself.NSWindowController can be used as the base class for auxiliary panel controllers in order to gain the useof its nib management abilities. One common standalone use of NSWindowController subclasses is ascontrollers for shared panels such as find panels, inspectors, or preferences panels. For example, the Sketchexample application uses NSWindowController subclasses for its various secondary panels. In this case,you can make an NSWindowController subclass that implements a shared instance method. For example,you could create aPreferencesController subclass with asharedPreferenceController class methodthat creates a single instance the first time it is called and returns that same instance on all subsequent calls.

Because your subclass derives from NSWindowController, you can just tell it the name of your preferencesnib file and it will handle loading the nib file and managing the window automatically. You add your ownoutlets and actions, as usual, to hook up the specific user interface for your panel and add methods to managethe panel’s behavior.

Subclassing Objects in the Document Architecture 572011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 58: MOSXAppProgrammingGuide

If you have multiple window controllers for a single document, you may want to explicitly control documentclosing. By default, a document closes when its last remaining window controller closes. However, if youwant the document to close when a particular window closes—the document’s “main” window, forexample—then you can send the main window controller a setShouldCloseDocument: message with avalue of YES.

You Rarely Need to Subclass NSDocumentController

Usually, you should not need to subclass NSDocumentController. Almost anything that can be done bysubclassing can be done just as easily by the application’s delegate. However, it is possible to subclassNSDocumentController if you need to.

For example, if you need to customize the Open panel, an NSDocumentController subclass is needed. Youcan override the NSDocumentController method runModalOpenPanel:forTypes: to customize thepanel or add an accessory view. The addDocument: and removeDocument: methods are provided forsubclasses that want to know when documents are opened or closed.

There are two ways to subclass NSDocumentController:

● You can make an instance of your subclass in your application’s main nib file. This instance becomes theshared instance.

● You can create an instance of your subclass in your application delegate’sapplicationWillFinishLaunching: method.

The first NSDocumentController object to be created becomes the shared instance. The AppKit frameworkcreates the shared instance (using the NSDocumentController class) during the “finish launching” phaseof application startup. So if you need a subclass instance, you must create it before AppKit does.

Xcode Provides a Document-Based Application Template

To expedite the development of document-based applications, Xcode provides a Cocoa Application projecttemplate with an option checkbox labeled Create Document-Based Application. This project template providesthe following things:

● A skeletal NSDocument subclass implementation

By default, the subclass of NSDocument is named MyBigDocument. The project includesMyBigDocument.h and MyBigDocument.m. The latter file includes commented blocks for importantmethods, including an init method that initializes and returns self, providing a location forsubclass-specific initialization. It also includes a fully implemented windowNibNamemethod that returnsthe name of the document window nib file, MyBigDocument, and an override ofwindowControllerDidLoadNib:. In addition, the template includes skeletal implementations of thedataOfType:error: andreadFromData:ofType:error:basic writing and reading methods showinghow to set the value of the NSError object passed as an indirect parameter.

● A nib file for the application's document

58 Xcode Provides a Document-Based Application Template2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 59: MOSXAppProgrammingGuide

This nib file is named MyBigDocument.xib (assuming you use the default subclass nameMyBigDocument). The subclass of NSDocument is made File’s Owner of the nib file. It has an outletnamed window connected to its window object. The window has only a text field on it, with the words"Your document contents here".

● The application’s main menu nib file

The main menu nib file, named MainMenu.xib, contains an application menu (named with theapplication’s name), a File menu (with all of its associated document commands), an Edit menu (withtext editing commands and Undo and Redo menu items), and Format, View, Window, and Help menus(with their own menu items representing commands). These menu items, as well as all of the menuitems of the File menu, are connected to the appropriate first-responder action methods. For example,the About menu item is connected to the orderFrontStandardAboutPanel: action method thatdisplays a standard About window.

See “Implementing the Application Menu Bar” (page 46) for more information about the main menunib file provided by the Xcode application templates.

● The application's information property list

The <applicationName>-Info.plist file contains placeholder values for global application keys, aswell as for the CFBundleDocumentTypes key, whose associated value is a dictionary containing key-valuepairs specifying information about the document types the application works with including theirNSDocument subclass.

The Xcode Cocoa Application project template dialog also provides an option checkbox labeled Use CoreData which, if used in conjunction with the Create Document-Based Application option, creates adocument-based application containing a subclass of NSPersistentDocument.

For a tutorial that shows how to implement a simple document-based application, see “Building a Text Editorin 15 Minutes”.

Supported Document Types Are Declared in the Application PropertyList

Applications use an information property list file, which is stored in the application’s bundle and named<applicationName>-Info.plist by default, to specify various information that can be used at runtime.Document-based applications use this property list to specify the document types the application can editor view. This information is used by the application and system entities such as the Finder and Launch Servicesas well.

For a new application, you should create a type with a name and extension that make sense for yourapplication. You can add more types as well. The application's “main,” or most important, document typeshould be listed first in the list of types. This is the type that NSDocumentController uses by default whenthe user asks for a new document.

For example, when the NSDocumentController object creates a new document or opens an existingdocument, it searches the property list for such items as the document class that handles a document type,the uniform type identifier (UTI) for the type, and whether the application can edit or only view the type.

Supported Document Types Are Declared in the Application Property List 592011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 60: MOSXAppProgrammingGuide

Similarly, Launch Services may use information about the icon file for the type. Document types informationis associated with the CFBundleDocumentTypes key as an array of dictionaries, each of which contains thekey-value pairs that define the document type.

If your application has some types that it can read but not write, you can declare this by setting the role forthose types to Viewer instead of Editor in Xcode. If your application has some types that it can write butnot read, you can declare this by using the NSExportableAs key. You can include the NSExportableAskey in the type dictionary for another type that your document class supports, usually the type dictionaryfor the most native type for your document class. Its value is an array of type names that your documentclass can write, but not read.

The Sketch example uses this key to allow it to export TIFF and EPS images even though it cannot read thosetypes. Write-only types can be chosen only when doing Save As operations. They are not allowed for Saveoperations.

Sometimes an application might understand how to read a type, but not how to write it, and when it readsdocuments of that type, it should automatically convert them to another type that you can write. An exampleof this would be an application that can read documents from an older version or from a competing product.It might want to read in the old documents and automatically convert them to the new native format. Thefirst step is to add the old type as a read-only type. By doing this, your application is able to open the oldfiles, but they come up as untitled files.

If you want to automatically convert them to be saved as your new type, you can override the readFrom...methods in your NSDocument subclass to call super and then reset the filename and type afterwards. Youshould use setFileType: and setFileURL: to set an appropriate type and name for the new document.When setting the filename make sure to strip the filename extension of the old type from the original filename,if it is there, and add the extension for the new type.

For more information about the property list, see “The Information Property List File” (page 80).

Multiple Document Types Use Multiple NSDocument Subclasses

The document architecture provides support for applications that handle multiple types of documents, eachtype using its own subclass of NSDocument. For example, you could have an application that enables usersto create text documents, spreadsheets, and other types of documents, all in a single application. Suchdifferent document types each require a different user interface encapsulated in a unique NSDocumentsubclass.

If your multiple-document-type application opens only existing documents, you can use the defaultNSDocumentController instance, because the document type is determined from the file being opened.However, if your application creates new documents, it needs to choose the correct type.

The NSDocumentController action method newDocument: creates a new document of the first type listedin the application’s array of document types configured in the Info.plist file. But this does not work forapplications that support several distinct types of document. If your application cannot determine whichtype to create depending on circumstances, you must provide a user interface allowing the user to choosewhich type of document to create.

You can create your own new actions, either in your application’s delegate or in an NSDocumentControllersubclass. You could create several action methods and have several different New menu items, or you couldhave one action that asks the user to pick a document type before creating a new one.

60 Multiple Document Types Use Multiple NSDocument Subclasses2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 61: MOSXAppProgrammingGuide

Once the user selects a type, your action method can use the NSDocumentController methodmakeUntitledDocumentOfType:error: to create a document of the correct type. After creating thedocument, your method should add it to the document controller's list of documents, and it should sendthe document makeWindowControllers and showWindows messages.

Alternatively, if you subclass NSDocumentController, you can override the defaultType method todetermine the document type and return it, when the user chooses New from the File menu.

The Document Architecture Has Built-in Undo Support

Undo is not always easy to implement, but at least the mechanism for implementing it is straightforward.By default, an NSDocument object has its own NSUndoManager object. The NSUndoManager class enablesyou to construct invocations that do the opposite of a previous action.

Implementing Undo

The key to implementing undo properly is to have well-defined primitives for changing your document. Eachmodel object, plus the NSDocument subclass itself, should define the set of primitive methods that canchange it. Each primitive method is then responsible for using the undo manager to enqueue invocationsthat undo the action of the primitive method. For example, if you decide that setColor: is a primitivemethod for one of your model objects, then inside of setColor: your object would do something like thefollowing:

[[[myDocument undoManager] prepareWithInvocationTarget:self] setColor:oldColor]

This message causes the undo manager to construct and save an invocation. If the user later chooses Undo,the saved invocation is invoked and your model object receives another setColor: message, this time withthe old color. You don’t have to keep track of whether commands are being undone to support redo. In fact,the way redo works is by watching what invocations get registered as the undo is happening and recordingthem on the redo stack.

You can use the setUndoManager: method if you need to use a subclass or otherwise need to change theundo manager used by the document.

Because many discrete changes might be involved in a user-level action, all the undo registrations thathappen during a single cycle of the event loop are usually grouped together and are undone all at once.NSUndoManager has methods that allow you to control the grouping behavior further if you need to.

Another aspect of good undo implementation is to provide action names so that the Undo and Redo menuitems can have more descriptive titles. Undo action names are usually best set in action methods instead ofthe change primitives in your model objects. This is because many primitive changes might go into one useraction, or different user actions might result in the same primitives being called in different ways. The Sketchexample application implements undo in action methods.

For more information on supporting undo in your application, see Undo Architecture.

The Document Architecture Has Built-in Undo Support 612011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 62: MOSXAppProgrammingGuide

Implementing Partial Undo

Because NSUndoManager does multiple-level undo, do not implement undo for only a subset of the possiblechanges to your document. The undo manager relies on being able to reliably take the document backthrough history with repeated undos. If some changes get skipped, the undo stack state is no longersynchronized with the contents of the document. Depending on your architecture, that situation can causeproblems that range from merely annoying to fatal.

For example, imagine that you have a drawing program that is able to undo a resize, but not a delete operation.If the user selects a graphic and resizes it, the undo manager gets an invocation that can undo that resizeoperation. Now the user deletes that graphic (which is not recorded for undo). If users now try to undo,nothing happens (at the very least), because the graphic that was resized is no longer there and undoingthe resize can’t have any visual effect. At worst, the application might crash trying to send a message to afreed object. So when you implement undo, remember that everything that causes a change to the documentshould be undoable.

If there are some changes that you cannot undo, there are two ways to handle the situation when a usermakes such a change. If you can be absolutely sure that the change has no relationship to any other changesthat can happen to the document (that is, something totally independent of all the rest of the contents ofthe document has changed), then you do not register any undo action for that change. On the other hand,if the change does have some relationship to the rest of the document contents, remove all actions from theundo manager when such a change takes place. Such changes then mark points of no return in your userexperience. When designing your application and document format, you should strive to avoid the need forthese “point of no return” operations.

Managing the Change Count

Because of undo support, the document must keep more information than just whether the document isdirty or clean. If a user opens a file, makes five changes, and then chooses Undo five times, the documentshould once again be clean. But if the user chooses Undo only four times, the document is still dirty.

The NSDocument object keeps a change count to deal with this. The change count can be modified bysending an updateChangeCount:message with one of the supported change types. The supported changesare NSChangeDone, NSChangeUndone, and NSChangeCleared. The NSDocument object itself clears thechange count whenever the user saves or reverts the document. If the document has an undo manager, itobserves the undo manager and automatically updates the change count when changes are done, undone,or redone.

Not Supporting Undo

If you don't want to support undo at all, first send the setHasUndoManager: message with a parametervalue of NO to your document. This causes the document never to get an undo manager.

Without an undo manager (and without undo support from your model objects), the document cannotautomatically track its dirty state. So, if you aren't implementing undo, you need to send anupdateChangeCount: message explicitly whenever your document is edited.

62 The Document Architecture Has Built-in Undo Support2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 63: MOSXAppProgrammingGuide

The Document Architecture Supports Robust Error Handling

Many NSDocument and NSDocumentController methods include as their last parameter an indirectreference to an NSError object. These are methods that create a document, write a file, access a resource,or perform a similar operation.

Two examples of NSDocumentController methods that take error parameters areopenUntitledDocumentAndDisplay:error:, which creates a new untitled document, andopenDocumentWithContentsOfURL:display:error:, which opens a document located by a URL. Incase of failure, these methods directly return nil and, in the last parameter, indirectly return an NSErrorobject that describes the error. Before calling such a method, client code that is interested in a possible errordeclares an NSError object variable and passes the address of the variable in the error parameter. If theclients are not interested in the error, they pass NULL in the error parameter.

Using NSError objects gives Cocoa applications the capability to present much more useful error messagesto the user, including detailed reasons for the error condition, suggestions for recovery, and even a mechanismfor attempting programmatic recovery. In addition, AppKit handles presenting the error to the user.

For detailed information about NSError handling see Error Handling Programming Guide.

Important: Cocoa methods that take error parameters in the Cocoa error domain are guaranteed to returnNSError objects. So, if you override such a method, you must adhere to the following rule: A method thattakes an error:(NSError **)outError argument must set the value of *outError to point to an NSErrorobject whenever the method returns a value that signals failure (typically nil or NO) and outError !=NULL.

If you override a method that takes an error parameter and you call the superclass implementation, you don'tneed to set outError yourself. Pass it the error argument that your override received when invoked.

If you override such a method to prevent some action but you don't want an error alert to be presented tothe user, return an error object whose domain is NSCocoaErrorDomain and whose code isNSUserCancelledError. The AppKit framework presents errors through the NSApplicationimplementations of the presentError: andpresentError:modalForWindow:delegate:didPresentSelector:contextInfo:methods declaredby NSResponder. Those implementations silently ignore errors whose domain is NSCocoaErrorDomainand whose code is NSUserCancelledError. So, for example, if your override ofopenDocumentWithContentsOfURL:display:error: wanted to avoid presenting an error to the user,it could set an error object as shown in the following fragment:

if (outError) { *outError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSUserCancelledError userInfo:nil];}

Documents Are Automatically Saved

In Mac OS X v10.7 and later, users don’t need to save documents explicitly or be concerned about losingunsaved changes. Instead, the system automatically writes document data to disk as necessary. YourNSDocument subclass opts into this behavior by overriding the autosavesInPlace class method to return

The Document Architecture Supports Robust Error Handling 632011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 64: MOSXAppProgrammingGuide

YES. The ideal baseline for saveless documents is this: The document data that users see in an applicationwindow is identical to the document on disk at all times. For practical reasons, the system does not attemptto save every change immediately, but it saves documents often enough and at the correct times to ensurethat the document in memory and the one on disk are effectively the same.

Part of the implementation of saveless documents is file coordination, a mechanism that serializes access tofiles among processes to prevent inconsistencies due to nonsequential reading and writing. Applicationsuse file coordination so that users don’t need to remember to save document changes before causing thedocument’s file to be read by another application. Document-based Cocoa applications use file coordinationautomatically.

Automatic document saving is supported by the implementation of autosaving in place. Autosaving in placeand autosaving elsewhere both protect against the user losing work due to application crashes, kernel panics,and power failures. However, autosaving in place differs from autosaving elsewhere in that it overwrites theactual document file rather than writing a new file next to it containing the autosaved document contents.(Autosaving in place performs a safe save by writing to a new file first, then moving it into the place of thedocument file when done.)

The document architecture still uses autosaving elsewhere to save untitled documents that have contentbut have not been explicitly saved and named by the user. In this case, untitled documents are autosavedin ~/Library/Autosave Information. In addition, NSDocument saves earlier revisions of documentselsewhere, giving the user access to previous versions.

The saveless-documents model automates crash protection but preserves the ability for users to savedocuments explicitly. It also automates maintenance of multiple older versions. Users can save immediatelyin the traditional way (by choosing File > Save or pressing Command-S). For an untitled document, an explicitSave command presents a dialog enabling the user to name the document and specify the location whereit is to be written to disk.

You should not invoke the autosavesInPlace method to find out whether autosaving is being done.Instead, the document architecture passes one of two new autosaving-related enumerators as anNSSaveOperationType parameter to your overrides of the NSDocumentmethods beginning with save...and write..., and you can examine those values. The autosave enumerators areNSAutosaveInPlaceOperation andNSAutosaveElsewhereOperation. The oldNSAutosaveOperationenumerator is equivalent to NSAutosaveElsewhereOperation and is deprecated in Mac OS X v10.7.

Before you enable autosaving, consider the saving performance of your application. If your application savesquickly, there is little reason not to enable it. But if your application saves slowly, enabling autosaving couldcause periodic blocking of your user interface while saving is happening. So, for example, if you have alreadyimplemented the autosaving behavior introduced in Mac OS X v10.4 (sending setAutosavingDelay: tothe NSDocumentController object with a nonzero value), then your application’s saving performance isprobably acceptable, and opting into autosaving in place is as simple as overriding autosavesInPlace toreturn YES. Otherwise, you may first need to address any issues with your document model or saving logicthat could hinder saving performance.

Document Saving Is Asynchronous

In Mac OS X v10.7 and later, NSDocument saves asynchronously, so that document data is written to a fileon a background thread. In this way, even if writing is slow, the application’s user interface remains responsive.You can override the method canAsynchronouslyWriteToURL:ofType:forSaveOperation: to return

64 Document Saving Is Asynchronous2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 65: MOSXAppProgrammingGuide

YES to enable asynchronous saving. In this case, NSDocument creates a separate writing thread and invokeswriteSafelyToURL:ofType:forSaveOperation:error: on it. However, the main thread remainsblocked until an object on the writing thread invokes the unblockUserInteraction method.

When unblockUserInteraction is invoked, the application resumes dequeueing user interface events,the user is able to continue editing the document, even if the writing of document data takes some time.The right moment to invoke unblockUserInteraction is when an immutable “snapshot” of the document’scontents has been taken, so that writing out the snapshot of the document’s contents can continue safelyon the writing thread while the user continues to edit the document on the main thread.

For more information on asynchronous document saving, see ApplicationKit ReleaseNotes (Lion) and commentsin the NSDocument header file.

Users Can Browse Document Versions

The document architecture implements the Versions feature of Mac OS X v10.7 in the behavior of NSDocument.An NSDocument subclass adopts autosaving in place by returning YES from +autosavesInPlace, asdescribed in “Documents Are Automatically Saved” (page 63), and adopting autosaving in turn enablesversion browsing.

After a document has been named and saved, the Save menu item and Command-S keyboard equivalentare replaced by the “Save a Version” menu item. This command saves a version of the document identifiedby date and time. The user can choose File > Revert to Saved, or choose Browse All Revisions from the pop-upmenu in the upper-right corner of the document title bar, to display a dialog enabling the user to choosebetween the last saved version or an older version. Choosing an older version displays a Time Machine–likeuser interface that selects among all of the document’s versions.

If the user chooses to restore a previous version, the current document contents are preserved on disk, ifnecessary, and the file's contents are replaced with those of the selected version. By holding the Option key,the user can also choose to restore a copy of a previous version, which does not affect the current documentcontents. The user can also select and copy contents from them and paste them into the current document.

When saving happens without user knowledge, it becomes easier for unintentional edits to get saved todisk, resulting in potential data loss. To help prevent autosaving unintentional edits, NSDocument tries todetermine when a user has opened a document to read it, but not edit it. For example, if the document hasnot been edited for some period of time, it is locked for editing and opened only for reading. (The periodafter editing when the document is locked is settable by a user preference.) When an edit is made to thedocument, NSDocument offers the user the choice of canceling the change, creating a new document withthe change, or allowing editing. A document that is preventing edits displays Locked in the upper-rightcorner of the title bar. The user can explicitly enable editing of the document by clicking on the Locked labeland choosing Unlock in the pop-up menu. A document that has been changed since it was last opened andis therefore being actively autosaved in place displays Edited in the titlebar instead of Locked.

Windows Are Restored Automatically

The document architecture implements the Resume feature of Mac OS X v10.7, as described in “User InterfacePreservation” (page 37), so that individual applications need to encode only information that is peculiar tothem and necessary to restore the state of their windows. The document architecture implements thefollowing steps in the window restoration process:

Users Can Browse Document Versions 652011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 66: MOSXAppProgrammingGuide

1. The NSWindowController method setDocument: sets the restoration class of document windowsto the class of the shared NSDocumentController object. The NSWindow object invalidates its restorablestate whenever its state changes by sending invalidateRestorableState to itself.

2. At the next appropriate time, Cocoa sends the window an encodeRestorableStateWithCoder:message, and the window encodes identification and status information into the passed-in encoder.

3. When the system restarts, Cocoa relaunches the application and sends therestoreWindowWithIdentifier:state:completionHandler: message to the NSApp applicationobject.

Applications can override this method to do any general work needed for window restoration, such assubstituting a new restoration class or loading it from a separate bundle.

NSApp decodes the restoration class for the window, sends therestoreWindowWithIdentifier:state:completionHandler: message to the restoration classobject, and returns YES.

4. The restoration class reopens the document and locates its window. Then it invokes the passed-incompletion handler with the window as a parameter.

5. Cocoa sends the restoreStateWithCoder: message to the window, which decodes its restorablestate from the passed-in NSCoder object and restores the details of its content.

Although the preceding steps describe only window restoration, in fact every object inheriting fromNSResponder has its own restorable state. For example, an NSTextView object stores the selected range(or ranges) of text in its restorable state. Likewise, an NSTabView object records its selected tab, anNSSearchField object records the search term, an NSScrollView object records its scroll position, andan NSApplication object records the z-order of its windows. An NSDocument object has state as well.Although NSDocument does not inherit from NSResponder, it implements many NSResponder methods,including these restoration methods.

When the application is relaunched, Cocoa sends the restoreStateWithCoder: message to the relevantobjects in turn, proceeding top-down: first to the NSApplication object, then to each NSWindow object,then to the NSWindowController object, then to the NSDocument object, and then to each view that hassaved state.

66 Windows Are Restored Automatically2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 3

Implementing a Document-Based Design

Page 67: MOSXAppProgrammingGuide

Enabling a window of your application to assume full-screen mode, taking over the entire screen, providesusers with a more immersive, cinematic experience. Full-screen appearance can be striking and can makeyour application stand out. From a practical standpoint, full-screen mode presents a better view of users’data, enabling them to concentrate fully on their content without the distractions of other applications orthe desktop.

In full-screen mode, by default, the menu bar and Dock are autohidden; that is, they are normally hiddenbut reappear when the user moves the pointer to the top or bottom of the screen. A full-screen windowdoes not draw its titlebar and may have special handling for its toolbar.

The full-screen experience makes sense for many applications but not for all. For example, the Finder, AddressBook, and Calculator would not provide any benefit to users by assuming full-screen mode. The same isprobably true for most utility applications. Media-rich applications, on the other hand, can often benefit fromfull-screen presentation.

Beginning with Mac OS X v10.7, Cocoa includes support for full-screen mode through APIs in NSApplication,NSWindow, and NSWindowDelegate protocol. When the user chooses to enter full-screen mode, Cocoadynamically creates a space and puts the window into that space. This behavior enables the user to haveone window of an application running in full-screen mode in one space, while using other windows of thatapplication, as well as other applications, on the desktop in other spaces. While in full-screen mode, the usercan switch between windows in the current application or switch applications.

Applications that have implemented full-screen user interfaces in previous versions of Mac OS X shouldconsider standardizing on the full-screen APIs in Mac OS X v10.7.

Full-Screen API in NSApplication

Full-screen support in NSApplication is provided by the presentation optionNSApplicationPresentationFullScreen. You can find the current presentation mode via theNSApplicationmethod currentSystemPresentationOptions, which is also key-value observable. Youcan set the presentation options using the NSApplicationmethod setPresentationOptions:. (Be sureto observe the restrictions on presentation option combinations documented withNSApplicationPresentationOptions, and set the presentation options in a try-catch block to ensurethat your program does not crash from an invalid combination of options.)

A window delegate may also specify that the window toolbar be removed from the window in full-screenmode and be shown automatically with the menu bar by includingNSApplicationPresentationAutoHideToolbar in the presentation options returned from thewindow:willUseFullScreenPresentationOptions: method of NSWindowDelegate.

Full-Screen API in NSApplication 672011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 4

Implementing the Full-Screen Experience

Page 68: MOSXAppProgrammingGuide

Full-Screen API in NSWindow

The application must specify whether a given window can enter full-screen mode. Applications can setcollection behavior using the setCollectionBehavior: method by passing in various constants, and thecurrent options may be accessed via the collectionBehavior method. You can choose between twoconstants to override the window collection behavior, as shown in the following table:

BehaviorConstant

The frontmost window with this collection behavior becomesthe full-screen window. A window with this collection behaviorhas a full-screen button in the upper right of its titlebar.

NSWindowCollection-BehaviorFullScreenPrimary

Windows with this collection behavior can be shown in the samespace with the full-screen window.

NSWindowCollection-BehaviorFullScreenAuxiliary

When a window goes into full-screen mode, the styleMask changes to NSFullScreenWindowMask toreflect the state of the window.The setting of the styleMask goes through the setStyleMask: method.As a result, a window can override this method if it has customization to do when entering or exiting full-screen.

A window can be taken into or out of full-screen mode using the toggleFullScreen: method. If anapplication supports full-screen mode, it should add a menu item to the View menu with toggleFullScreen:as the action, and nil as the target.

Full-Screen API in NSWindowDelegate Protocol

The following notifications are sent before and after the window enters and exits full-screen mode:

NSWindowWillEnterFullScreenNotificationNSWindowDidEnterFullScreenNotificationNSWindowWillExitFullScreenNotificationNSWindowDidExitFullScreenNotification

The window delegate has the following corresponding window delegate notification methods:

windowWillEnterFullScreen:

windowDidEnterFullScreen:

windowWillExitFullScreen:

windowDidExitFullScreen:

The NSWindowDelegate protocol methods supporting full-screen mode are listed in Table 4-1.

68 Full-Screen API in NSWindow2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 4

Implementing the Full-Screen Experience

Page 69: MOSXAppProgrammingGuide

Table 4-1 Window delegate methods supporting full-screen mode

DescriptionMethod

Invoked to allow the delegate tomodify the full-screen content size.

window: willUseFullScreenContentSize:

Returns the presentation options thewindow will use when transitioning tofull-screen mode.

window: willUseFullScreenPresentationOptions:

Invoked when the window is about toenter full-screen mode.

customWindowsToEnterFullScreenForWindow:

Invoked to start the window animationinto full-screen mode, includingtransitioning to a new space. You canimplement this method to performcustom animation with the givenduration to be in sync with the systemanimation.

window:startCustomAnimationToEnterFullScreenWithDuration:

Invoked if the window failed to enterfull-screen mode.

windowDidFailToEnterFullScreen:

The system has started its animationout of full-screen mode, includingtransitioning back to the desktopspace. You can implement this methodto perform custom animation with thegiven duration to be in sync with thesystem animation.

customWindowsToExitFullScreenForWindow:

Invoked when the window is about toexit full-screen mode.

window:startCustomAnimationToExitFullScreenWithDuration:

Invoked if the window failed to exitfull-screen mode.

windowDidFailToExitFullScreen:

For details, see NSWindowDelegate Protocol Reference and the Application Kit Release Notes (Lion).

Full-Screen API in NSWindowDelegate Protocol 692011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 4

Implementing the Full-Screen Experience

Page 70: MOSXAppProgrammingGuide

70 Full-Screen API in NSWindowDelegate Protocol2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 4

Implementing the Full-Screen Experience

Page 71: MOSXAppProgrammingGuide

During the design phase of creating your application, you need to think about how to implement certainfeatures that users expect in well-formed Mac OS X applications. Integrating these features into your applicationarchitecture can have an impact on the data model or may require cooperation between significantly differentportions in the application.

You Can Prevent the Automatic Relaunch of Your Application

By default, as part of the Resume feature of Mac OS X v10.7, applications that were open at logout arerelaunched by the system when the user logs in again. You can prevent the automatic relaunching of yourapplication at login by sending it a disableRelaunchOnLogin message. This NSApplication methodincrements a counter that controls the application being relaunched; if the counter is 0 at the time the userlogs out, then the app is relaunched when the user logs back in. The counter is initially zero, providing thedefault relaunch behavior.

Your can reinstate automatic relaunching of your application by sending it an enableRelaunchOnLoginmessage. This message decrements the relaunch counter, so an equal number of disableRelaunchOnLoginand enableRelaunchOnLogin messages enables relaunching. Both methods are thread safe.

If your application should not be relaunched because it launches via some other mechanism, such as thelaunchd system process, then the recommended practice is to send the application adisableRelaunchOnLogin message once, and never pair it with an enableRelaunchOnLogin message.

If your application should not be relaunched because it triggers a restart (for example, if it is an installer),then the recommended practice is to send it a disableRelaunchOnLogin message immediately beforeyou attempt to trigger a restart and send it an enableRelaunchOnLogin message immediately after. Thisprocedure handles the case where the user cancels restarting; if the user later restarts for another reason,then your application should be relaunched.

Making Your Application Accessible Enables Many Users

Millions of people have a disability or special need. These include visual and hearing impairments, physicaldisabilities, and cognitive and learning challenges. Access to computers is vitally important for this population,because computers can provide a level of independence that is difficult to attain any other way. As populationsaround the world age, an increasing number of people will experience age-related disabilities, such as visionor hearing loss. Current and future generations of the elderly will expect to be able to continue using theircomputers and accessing their data, regardless of the state of their vision and hearing. Applications thatsupport customizable text displays, access by a screen reader, or the replacement of visual cues by audibleones can serve this population well.

You Can Prevent the Automatic Relaunch of Your Application 712011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 72: MOSXAppProgrammingGuide

Mac OS X is designed to accommodate assistive technologies and has many built-in features to help peoplewith disabilities. Users access most of this functionality through the Universal Access pane of SystemPreferences. Some of these built-in technologies take advantage of the same accessibility architecture thatallows external assistive technologies to access your application. Designing your application with accessibilityin mind not only allows you to reach a larger group of users, it results in a better experience for all your users.

As a first step in designing your application, be sure to read Mac OS X Human Interface Guidelines. That bookprovides detailed specifications and best practices for designing and implementing an intuitive, consistent,and aesthetically pleasing user interface that delivers the superlative experience Macintosh users have cometo expect. During the design process, you also should be aware of the accessibility perspective on many basicdesign considerations. Consider the following basic accessibility-related design principles:

● Support full keyboard navigation. For many users, a mouse is difficult, if not impossible, to use.Consequently, a user should be able to perform all your application’s functions using the keyboard alone.

● Don’t override built-in keyboard shortcuts. This applies both to the keyboard shortcuts Mac OS Xreserves (listed in “Keyboard Shortcuts Quick Reference”) and to the accessibility-related keyboardshortcuts (listed in “Accessibility Keyboard Shortcuts”). As a general rule, you should never overridereserved keyboard shortcuts. In particular, you should take care not to override accessibility-relatedkeyboard shortcuts or your application will not be accessible to users who enable full keyboard access.

A corollary to this principle is to avoid creating too many new keyboard shortcuts that are specific toyour application. Users should not have to memorize a new set of keyboard commands for eachapplication they use.

● Provide alternatives for drag-and-drop operations. If your application relies on drag-and-drop operationsin its workflow, you should provide alternate ways to accomplish the same tasks. This may not be easy;in fact, it may require the design of an alternate interface for applications that are heavily dependent ondrag and drop.

● Make sure there’s always a way out of your application’s workflow. This is important for all users, ofcourse, but it’s essential for users of assistive technologies. A user relying on an assistive application touse your application may have a somewhat narrower view of your application’s user interface. For thisreason, it’s especially important to make canceling operations and retracing steps easy.

In addition to the basic design principles, you should consider the requirements of specific disabilities andresulting design solutions and adaptations you can implement. The main theme of these suggestions is toprovide as many alternate modes of content display as possible, so that users can find the way that suitstheir needs best. Consider the following categories of disabilities:

● Visual Disabilities. Visual disabilities include blindness, color blindness, and low vision. Make yourapplication accessible to assistive applications, such as screen readers. Ensure that color is not the onlysource of come particular information in your user interface. Provide an audio option for all visual cuesand feedback, as well as succinct descriptions of images and animated content.

● Hearing Disabilities. When you design the audio output of your application, remember that some usersmay not be able to hear your application’s sound effects well or at all. And, of course, there are situationsin which any user could not use audio output effectively, such as in a library. Providing redundant audioand visual output can aid comprehension for users with other types of disabilities as well, such as cognitiveand learning disabilities.

72 Making Your Application Accessible Enables Many Users2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 73: MOSXAppProgrammingGuide

● Motor and Cognitive Disabilities. People with motor disabilities may need to use alternatives to thestandard mouse and keyboard input devices. Other users may have difficulty with the fine motor controlrequired to double-click a mouse or to press key combinations on the keyboard. Users with cognitiveor learning disabilities may need extra time to complete tasks or respond to alerts.

Mac OS X provides support for many types of disabilities at the system level through solutions offered in theUniversal Access system preferences, illustrated in Figure 5-1. In addition, most standard Cocoa objectsimplement accessibility through the NSAccessibility protocol, providing reasonable default behavior inmost cases, Cocoa applications built with standard objects are automatically accessible. In general, you needto explicitly implement the NSAccessibility protocol methods only if you subclass one of them, addingnew behavior.

Figure 5-1 Universal Access system preference dialog

The NSAccessibility informal protocol defines methods that Cocoa classes must implement to makethemselves available to an external assistive application. An assistive application interacts with your applicationto allow persons with disabilities to use your application. For example, a person with a visual impairmentcould use an application to convert menu items and button labels into speech and then perform actions byverbal command.

An accessible object is described by a set of attributes that define characteristics such as the object type, itsvalue, its size and position on the screen, and its place in the accessibility hierarchy. For some objects, theset of attributes can include parameterized attributes. Parameterized attributes behave similar to a functionby allowing you to pass a parameter when requesting an attribute value.

For more information, see Accessibility Overview.

Making Your Application Accessible Enables Many Users 732011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 74: MOSXAppProgrammingGuide

Provide User Preferences for Customization

Preferences are settings that enable users to customize the appearance or behavior of your software. TheMac OS X user defaults system lets you access and manage user preferences. You can use the defaults systemto provide reasonable initial values for application settings, as well as save and retrieve the user's ownpreference selections across sessions. The Cocoa NSUserDefaults class provides programmatic access tothe user defaults system.

The NSUserDefaults class provides convenience methods for accessing common types such as floats,doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or forcollections a combination of instances of ): NSData, NSString, NSNumber, NSDate, NSArray, orNSDictionary. If you want to store any other type of object, you should typically archive it to create aninstance of NSData.

The user defaults system groups defaults into domains. Two of the domains are persistently saved in theuser defaults database: the application domain stores application-specific defaults, and the global domainstores defaults applicable to all applications. In addition, the user defaults system provides three volatiledomains whose values last only while the user defaults object exists: the argument domain for defaults setfrom command-line arguments, the languages domain containing defaults for a locale if one is specified,and the registration domain for “factory defaults” registered by the application.

Your application uses the NSUserDefaults class to register default preferences, and typically it also providesa user interface (a preferences panel) that enables the user to change those preferences. Preferences arestored in the ~/Library/Preferences/ folder in a standard XML-format property list file as a set of key-valuepairs. The application-specific preferences property list is identified by the bundle identifier of the application.

For more details, see Preferences and Settings Programming Guide.

Integrate Your App With Spotlight Search

Spotlight is a fast desktop search technology that allows users to organize and search for files based onmetadata. Metadata is data about a file, rather than the actual content stored in the file. Metadata can includefamiliar information such as an asset’s author and modification date but it can also be keywords or otherinformation that is custom to a particular asset. For example, an image file might have metadata describingthe image’s dimensions and color model.

Developers of applications that save documents to disk should consider providing Spotlight support byimplementing a metadata importer. A Spotlight metadata importer is a small plug-in bundle that you createto extract information from files created by your application. Spotlight importers are used by the Spotlightserver to gather information about new and existing files, as illustrated in Figure 5-2.

74 Provide User Preferences for Customization2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 75: MOSXAppProgrammingGuide

Figure 5-2 Spotlight extracting metadata

System Store

SpotlightSpotlight Importers

MDItemkMDItemTitlekMDItemAuthorskMDItemCopyright

...

Spotlight Importers

Apple provides importers for many standard file types that the system uses, including RTF, JPEG, Mail, PDFand MP3. However, if you define a custom document format, you must create a metadata importer for yourown content. Xcode provides a template for writing Spotlight importer plug-ins. For information aboutwriting a Spotlight importer, see Spotlight Importer Programming Guide.

In addition, you may wish to provide metadata search capability in your application. Cocoa provides theNSMetadataQuery class which enables you to construct queries using a subset of the NSPredicate classesand execute the queries asynchronously. For information about providing Spotlight search capability in yourapplication, see File Metadata Search Programming Guide.

For more information about Spotlight, see Spotlight Overview.

Use Services to Increase Your Application’s Usefulness

Services allow a user to access the functionality of one application from within another application. Anapplication that provides a service advertises the operations it can perform on a particular type of data—forexample, encryption of text, optical character recognition of a bitmapped image, or generating text such asa message of the day. When the user is manipulating that particular type of data in some application, theuser can choose the appropriate item in the Services menu to operate on the current data selection (or merelyinsert new data into the document).

See Services Implementation Guide for more information.

Make Use of Resolution Independence

Resolution independence decouples the resolution of the user's screen from the units you use in your code’sdrawing operations. While Mac OS X v10.4 and earlier assumed a screen resolution of 72 dots per inch (dpi),most modern screens actually have resolutions that are 100 dpi or more. The result of this difference is thatcontent rendered for a 72-dpi screen appears smaller on such screens and will appear smaller yet as screenresolutions increase on future displays.

Use Services to Increase Your Application’s Usefulness 752011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 76: MOSXAppProgrammingGuide

For applications that depend on a graphical user interface, the dwindling size of user interface elements canmake them too small for users to interact with effectively. For example, a checkbox might be too small toclick easily. The solution is to make the drawing sizes specified by the application independent of the display'spixel resolution and allow arbitrary scaling between the two. Depending on the type of application, the userinterface, and the drawing technologies used, you may need to update your code to provide the best userexperience on a resolution-independent system.

Cocoa applications require little work to support resolution independence because the Cocoa frameworkshandle the scaling for you. Standard Cocoa controls, such as buttons and checkboxes, automatically scalecorrectly. However, depending on how you manipulate windows and the views within them, you may needto make some changes. In addition, you may need to provide high-resolution versions of any custom artwork.

If you draw directly to the screen on a pixel-by-pixel basis, you need to obtain the current scale factor andscale all your images manually. To obtain the scale factor for a particular window, use theuserSpaceScaleFactor method in the NSWindow class.

In some cases, you may need to convert rectangles or points from the coordinate system of one NSViewinstance to another (typically the superview or subview), or from one NSView instance to the containingwindow. The NSView class defines methods for this purpose and, in Mac OS X v10.5 and later, methods thatshould be used when performing pixel alignment of view content. See Cocoa Drawing Guide and ViewProgramming Guide for more information about coordinate systems.

Make sure your application's custom artwork can scale properly as the pixel density of displays increases.That is, the art needs to be larger in terms of pixel dimensions to avoid loss of resolution at high scale factorsonscreen. For example, application icons, custom buttons and other controls, and custom images may needhigh-resolution versions of their artwork. If an existing standard control or icon provides the same functionas your custom version, you should consider adopting the standard version.

For application icons, you should make sure that the icon family includes images up to 512 x 512 pixels. Fornew icons, it’s easiest to design the large icons first and then scale them down. You can use the Icon Composerutility available in the /Developer/Applications/Utilities/ folder to create your icons. Icon Composerv2.0 and later includes support for larger icon sizes.

For more information about resolution independence, see Resolution Independence Guidelines.

Prepare for Fast User Switching

Fast user switching lets users share a single machine without having to log out every time they want to accesstheir user account. Users share physical access to the machine, including the same keyboard, mouse, andmonitor. However, instead of logging out, a new user simply logs in and switches out the previous user.

Processes in a switched-out login session continue running as before. They can continue processing data,communicating with the system, and drawing to the screen buffer as before. However, because they areswitched out, they do not receive input from the keyboard and mouse. Similarly, if they were to check, themonitor would appear to be in sleep mode. As a result, it may benefit some applications to adjust theirbehavior while in a switched-out state to avoid wasting system resources.

While fast user switching is a convenient feature for users, it does provide several challenges for applicationdevelopers. Applications that rely on exclusive access to certain resources may need to modify their behaviorto live in a fast user switching environment. For example, an application that stores temporary data in /tmpmay run into problems when a second instance running under a different user tries to modify the same filesin that directory.

76 Prepare for Fast User Switching2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 77: MOSXAppProgrammingGuide

To support fast user switching, there are certain guidelines you should follow in developing your applications,most of which describe safe ways to identify and share system resources. A summary of these guidelines isas follows:

● Incorporate session ID information into the name of any entity that appears in a global namespace,including file names, shared memory regions, semaphores, and named pipes.

Tagging such application-specific resources with a session ID is necessary to distinguish them fromsimilar resources created by applications in a different session. The Security layer of the system assignsa unique ID to each login session. Incorporating this ID into cache file or temporary directory names canprevent namespace collisions when creating these files. See “Supporting Fast User Switching” forinformation on how to get the session ID.

● Don't assume you have exclusive access to any resource, especially TCP/IP ports and hardware devices.

● Don't assume there is only one instance of a per-user service running.

● Use file-level or range-level locks when accessing files.

● Accept and handle user switch notifications. See “User Switch Notifications” for more information.

For more information on user switching, see Multiple User Environments.

Take Advantage of the Dock

The Dock is a desktop application designed to reduce desktop clutter, provide users with feedback about anapplication, and allow users to switch easily between tasks. You can customize your application Dock tile bymodifying the Dock icon and adding items to the menu displayed for your application, and you can customizethe Dock icon of a minimized window.

An application’s Dock icon is, by default, the application’s icon. While your application is running, you canmodify or replace the default icon with another image that indicates the current state of your application.For example, the icon for Mail changes when messages are waiting to be read. A badge—the red circle andnumber in the figure—is overlaid onto Mail’s application icon to indicate the number of unread messages.The number changes each time Mail retrieves more messages.

When the user holds the Control key down and clicks on a Dock tile, a menu appears. If your application doesnothing to customize the menu, the application Dock tile’s menu contains a list of the application’s opendocuments (if any), followed by the standard menu items Keep in Dock, Open at Login, Show in Finder, Hide,and Quit. You can add other menu items to the Dock menu, either statically by providing a custom menunib file, or dynamically by overriding the application delegate’s applicationDockMenu: method.

You can also customize a dock tile when your application is not currently running by creating a Dock tileplug-in that can update the Dock tile icon and menu. For example, you may want to update the badge textto indicate that new content will be available the next time the application is launched, and you may wantto customize the application’s Dock menu to deal with the new content.

For information explaining how to customize your application’s Dock icon and menu, see Dock TileProgramming Guide.

Take Advantage of the Dock 772011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 78: MOSXAppProgrammingGuide

78 Take Advantage of the Dock2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 5

Supporting Common Application Behaviors

Page 79: MOSXAppProgrammingGuide

Configuring your application properly is an important part of the development process. Mac OS X applicationsuse a structured directory configuration to manage their code and resource files. And although most of thefiles are custom and are there to support your application, some are required by the system or the App Storeand must be configured properly.

All of the requirements for preparing your application and distributing it on the App Store are described inthe App Store Resource Center.

Configuring Your Xcode Project

To develop a Mac OS X application, you create an Xcode project. An Xcode Project is a repository for all thefiles, resources, and information required to build your application (or one of a number of other softwareproducts). A project contains all the elements used to build your application and maintains the relationshipsbetween those elements. It contains one or more targets, which specify how to build the software. A projectdefines default build settings for all the targets in the project (each target can also specify its own buildsettings, which override the project build settings).

You create a new project using the Xcode File > New > New Project menu command, which invokes the NewProject dialog. This dialog enables you to choose a template for your project, such as a Cocoa application,to name it, and to locate it in your file system. The New Project dialog also provides options, so you canspecify whether your application uses the Cocoa document architecture or the Core Data framework. Whenyou save your project, Xcode lets you to create a local Git repository to enable source code control for yourproject.

If you have two or more closely related projects, you should create an Xcode Workspace and add your projectsto it. A workspace groups projects and other documents so you can work on them together. One project canuse the products and shared libraries of another project while building, and Xcode does indexing across theentire workspace, extending the scope of content-aware features such as code completion.

Once you have created your project, you write and edit your code using the Xcode source editor. You alsouse Xcode to build and debug your code, setting breakpoints, viewing the values of variables, steppingthrough running code, and reviewing issues found during builds or code analysis.

When you create a new project, it includes one or more targets, where each target specifies one build productand the instructions for how the product is to be built. Most developers never need to change the defaultof the vast majority of build settings, but there are a few basic settings that you should check for each target,such as the deployment target (platform, OS version, and architecture), main user interface, and linkedframeworks and libraries.

You also need to set up one or more schemes to specify the targets, build configuration, and executableconfiguration to use when the product specified by the target is launched. You use the project editor andthe scheme editing dialog to edit build settings and control what happens when you build and run yourcode. “Building and Running Your Code” explains how to work with Xcode build settings and schemes.

Configuring Your Xcode Project 792011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 6

Build-Time Configuration Details

Page 80: MOSXAppProgrammingGuide

For more information about using Xcode to create, configure, build, and debug your project, as well asarchiving your program to package it for distribution or submission to the Mac App Store, see Xcode 4 UserGuide.

The Information Property List File

An information property list (Info.plist) file contains essential runtime-configuration information for theapplication. Xcode provides a version of this file with every Mac OS X application project and configures itwith several standard keys. Although the default keys cover several important aspects of the application’sconfiguration, most applications require additional keys to specify their configuration fully.

To view the contents of your Info.plist file, select it in the Groups & Files pane. Xcode displays a propertylist editor similar to the one in Figure 6-1 (which is from Xcode 3.2.5). You can use this window to edit theproperty values and add new key-value pairs. By default, Xcode displays a more user-friendly version of eachkey name. To see the key names that Xcode adds to the Info.plist file, Control-click an item in the editorand choose Show Raw Keys/Values from the contextual menu that appears.

Figure 6-1 The information property list editor

Xcode automatically adds some important keys to the Info.plist file of all new projects and sets theirinitial values. However, there are several keys that Mac OS X applications use commonly to configure theirlaunch environment and runtime behavior. Here are some keys that you might want to add to yourapplication’s Info.plist file specifically for Mac OS X:

● LSApplicationCategoryType (required for applications distributed using the App Store)

80 The Information Property List File2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 6

Build-Time Configuration Details

Page 81: MOSXAppProgrammingGuide

● CFBundleDisplayName

● LSHasLocalizedDisplayName

● NSHumanReadableCopyright

● LSMinimumSystemVersion

● UTExportedTypeDeclarations

● UTImportedTypeDeclarations

For detailed information about these and other keys that you can include in your application’s Info.plistfile, see Information Property List Key Reference.

The Mac OS X Application Bundle

When you build your Mac OS X application, Xcode packages it as a bundle. A bundle is a directory in the filesystem that groups related resources together in one place. A Mac OS X application bundle contains a singleContents directory, inside of which are additional files and directories with the application’s code, resources,and localized content. Table 6-1 lists the contents of a typical Mac OS X application bundle, which fordemonstration purposes is called MyApp. This example is for illustrative purposes only. Some of the files listedin this table may not appear in your own application bundles.

Table 6-1 A typical application bundle

DescriptionFiles

The executable file containing yourapplication’s code. The name of this file isthe same as your application name minusthe .app extension.

This file is required.

Contents/MacOS/MyApp

Also known as the information property listfile, a file containing configuration data forthe application. The system uses this data todetermine how to interact with theapplication at specific times.

This file is required. For more information,see “The Information Property List File” (page80).

Contents/Info.plist

The Mac OS X Application Bundle 812011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 6

Build-Time Configuration Details

Page 82: MOSXAppProgrammingGuide

DescriptionFiles

The English version of the application’s mainnib file. This file contains the default interfaceobjects to load at application launch time.Typically, this nib file contains theapplication’s menu bar and applicationdelegate object. It may also contain othercontroller objects that should always beavailable at launch time. (The name of themain nib file can be changed by assigning adifferent value to the NSMainNibFile keyin the Info.plist file.)

This file is optional but recommended. Formore information, see “The InformationProperty List File” (page 80)

Contents/Resources/English.lproj/MainMenu.nib

Nonlocalized resources are placed at the toplevel of the Resources directory (sun.pngrepresents a nonlocalized image file in theexample). The application uses nonlocalizedresources when no localized version of thesame resource is provided. Thus, you can usethese files in situations where the resourceis the same for all localizations.

Contents/Resources/sun.png (or other resource files)

Localized resources are placed insubdirectories with an ISO 639-1 languageabbreviation for a name plus an .lprojsuffix. Although more human readable names(such as English.lproj, French.lproj,and German.lproj) can be used fordirectory names, the ISO 639-1 names arepreferred because they allow you to includean ISO 3166-1 regional designation. (Forexample, the en_GB.lproj directorycontains resources localized for English asspoken in Great Britain, the es.lprojdirectory contains resources localized forSpanish, and the de.lproj directorycontains resources localized for German.)

Contents/Resources/en_GB.lproj

Contents/Resources/es.lproj

Contents/Resources/de.lproj

Other language-specific project directories

A Mac OS X application should be internationalized and have a language.lproj directory for each languageit supports. Even if you provide localized versions of your resources, though, include a default version ofthese files at the top level of your Resources directory. The default version is used when a specific localizationis not available.

At runtime, you can access your application’s resource files from your code using the following steps:

1. Obtain a reference to your application’s main bundle object (typically using theNSBundle class).

2. Use the methods of the bundle object to obtain a file-system path to the desired resource file.

82 The Mac OS X Application Bundle2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 6

Build-Time Configuration Details

Page 83: MOSXAppProgrammingGuide

3. Open (or access) the file and use it.

You obtain a reference to your application’s main bundle using the mainBundle class method of NSBundle.The pathForResource:ofType: method is one of several NSBundle methods that you can use to retrievethe location of resources. The following example shows how to locate a file called sun.png and create animage object using it. The first line gets the bundle object and the path to the file. The second line createsan NSImage object that you could use to display the image in your application.

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"sun" ofType:@"png"];NSImage* sunImage = [[NSImage alloc] initWithContentsOfFile:imagePath];

Note: If you prefer to use Core Foundation to access bundles, you can obtain a CFBundleRef opaque typeusing the CFBundleGetMainBundle function. You can then use that opaque type plus the Core Foundationfunctions to locate any bundle resources.

For information on how to access and use resources in your application, see Resource Programming Guide.For more information about the structure of a Mac OS X application bundle, see Bundle Programming Guide.

Internationalizing Your Application

The process of preparing a project to handle content in different languages is called internationalization.The process of converting text, images, and other content into other languages is called localization. Projectresources that are candidates for localization include:

● Code-generated text, including locale-specific aspects of date, time, and number formatting

● Static text—for example, strings you specify programmatically and display in parts of your user interfaceor an HTML file containing application help

● Icons (including your application icon) and other images when those images either contain text or havesome culture-specific meaning

● Sound files containing spoken language

● Nib files

Users select their preferred language from the Language and Text system preference, shown in Figure 6-2.

Internationalizing Your Application 832011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 6

Build-Time Configuration Details

Page 84: MOSXAppProgrammingGuide

Figure 6-2 The Language preference view

Your application bundle can include multiple language-specific resource directories. The names of thesedirectories consist of three components: an ISO 639-1 language code, an optional ISO 3166-1 region code,and a .lproj suffix. For example, to designate resources localized to English, the bundle would be nameden.lproj. By convention, these directories are called lproj directories.

Note: You may use ISO 639-2 language codes instead of those defined by ISO 639-1. For more informationabout language and region codes, see “Language and Locale Designations” in InternationalizationProgrammingTopics.

Each lproj directory contains a localized copy of the application’s resource files. When you request the pathto a resource file using the NSBundle class or the CFBundleRef opaque type, the path you get backautomatically reflects the resource for the user’s preferred language.

For more information about internationalization and how you support localized content in your Mac OS Xapplications, see Internationalization Programming Topics.

84 Internationalizing Your Application2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 6

Build-Time Configuration Details

Page 85: MOSXAppProgrammingGuide

As you develop your application and your project code stabilizes, you can begin performance tuning. Ofcourse, you want your application to launch and respond to the user’s commands as quickly as possible. Aresponsive application fits easily into the user’s workflow and feels well crafted.

Speed Up Your Application’s Launch Time

You can improve your application’s performance at launch time by minimizing or deferring work until afterthe launch sequence has completed. The launch of an application provides users with the first impressionof your application, and it’s something they see on a regular basis.

Your overriding goal during launch should be to display the application’s menu bar and main window andthen start responding to user commands as quickly as possible. Making your application responsive tocommands quickly provides a better experience for the user. The following sections provide some generaltips on how to make your application launch faster.

Delay Initialization Code

Many applications spend a lot of time initializing code that isn’t used until much later. Delaying the initializationof subsystems that are not immediately needed can speed up your launch time considerably. Rememberthat the goal is to display your application interface quickly, so try to initialize only the subsystems relatedto that goal initially.

Once you have posted your interface, your application can continue to initialize additional subsystems asneeded. However, remember that just because your application is able to process commands does not meanyou need all of that code right away. The preferred way of initializing subsystems is on an as-needed basis.Wait until the user executes a command that requires a particular subsystem and then initialize it. That way,if the user never executes the command, you will not have wasted any time running the code to prepare forit.

Avoid putting a lot of extraneous initialization code in your awakeFromNib methods. The system calls theawakeFromNib method of your main nib file before your application enters its main event loop. Use thatmethod to initialize the objects in that nib and to prepare your application interface. For all other initialization,use the applicationDidFinishLaunching: method of your NSApplicationDelegate object instead.For more information on nib files and how they are loaded, see Resource Programming Guide.

Speed Up Your Application’s Launch Time 852011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 7

Tuning for Performance and Responsiveness

Page 86: MOSXAppProgrammingGuide

Simplify Your Main Nib File

Loading a nib file is an expensive process that can slow down your application launch time if you are notcareful. When a nib file is loaded, all of the objects in that file are instantiated and made ready for use. Themore objects you include in your application’s main nib, the more time it takes to load that file and launchyour application.

The instantiation process for objects in a nib file requires that any frameworks used by those objects mustthemselves reside in memory. Thus loading a nib for a Cocoa application would likely require the loading ofboth the AppKit and Foundation frameworks, if they were not already resident in memory. Similarly, if youdeclare a custom class in your main nib file and that class relies on other frameworks, the system must loadthose frameworks as well.

When designing your application’s main nib file, you should include only those objects needed to displayyour application’s initial user interface. Usually, this would involve just your application’s menu bar and initialwindow. For any custom classes you include in the nib, make sure their initialization code is as minimal aspossible. Defer any time-consuming operations or memory allocations until after the class is instantiated.

Minimize Global Variables

For both applications and frameworks, be careful not to declare global variables that require significantamounts of initialization. The system initializes global variables before calling your application’s main routine.If you use a global variable to declare an object, the system must call the constructor or initialization methodfor that object during launch time. In general, it’s best to avoid declaring objects as global variables altogetherwhen you can use a pointer instead.

If you are implementing a framework or any type of reusable code module, you should also minimize thenumber of global variables you declare. Each application that links to a framework acquires a copy of thatframework’s global variables. These variables might require several pages of virtual memory, which thenincreases the memory footprint of the application. An increased memory footprint can lead to paging in theapplication, which has a tremendous impact on performance.

One way to minimize the global variables in a framework is to store the variables in a malloc-allocated blockof memory instead. In this technique, you access the variables through a pointer to the memory, which youstore as a global variable. Another advantage of this technique is that it allows you to defer the creation ofany global variables until the first time they are actually used. See “Tips for Allocating Memory” in MemoryUsage Performance Guidelines for more information.

Minimize File Access at Launch Time

Accessing a file is one of the slowest operations performed on a computer, so it is important that you do itas little as possible, especially at launch time. There is always some file access that must occur at launch time,such as loading your executable code and reading in your main nib file, but reducing your initial dependenceon startup files can provide significant speed improvements.

If you can delay the reading of a file until after launch time, do so. The following list includes some files whosecontents you may not need until after launch:

● Frameworks not used directly by your application—Avoid calling code that uses nonessential frameworksuntil after launch.

86 Speed Up Your Application’s Launch Time2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 7

Tuning for Performance and Responsiveness

Page 87: MOSXAppProgrammingGuide

● Nib files whose contents are not displayed immediately—Make sure your nib files and awakeFromNib:code are not doing too much at launch time. See “Simplify Your Main Nib File” (page 86) for moreinformation.

● User preference files—User preferences may not be local so read them later if you can.

● Font files—Consider delaying font initialization until after the application has launched.

● Network files—Avoid reading files located on the network if at all possible.

If you must read a file at launch time, do so only once. If you need multiple pieces of data from the same file,such as from a preferences file, consider reading all of the data once rather than accessing the file multipletimes.

Don’t Block the Main Thread

The main thread is where your application handles user events and other input, so you should keep it freeas much as possible to be responsive to the user. In particular, never use the main thread to performlong-running or potentially unbounded tasks, such as tasks that require network access. Instead, always movethose tasks onto background threads. The preferred way to do so is to use Grand Central Dispatch (GCD) oroperation objects to perform tasks asynchronously.

For more information about doing work on background threads, see Concurrency Programming Guide.

Decrease Your Application’s Code Size

In the context of performance, the more memory your application occupies, the more inefficient it is. Morememory means more memory allocations, more code, and a greater potential for paging.

Reducing your code footprint is not just a matter of turning on code optimizations in your compiler, althoughthat does help. You can also reduce your code footprint by organizing your code so that only the minimumset of required functions is in memory at any given time. You implement this optimization by profiling yourcode.

See “Memory Instruments” in InstrumentsUserGuide for information about profiling your application’s memoryallocations.

Compiler-Level Optimizations

The Xcode compiler supports optimization options that let you choose whether you prefer a smaller binarysize, faster code, or faster build times. For new projects, Xcode automatically disables optimizations for thedebug build configuration and selects the Fastest, Smallest option for the release build configuration. Codeoptimizations of any kind result in slower build times because of the extra work involved in the optimizationprocess. If your code is changing, as it does during the development cycle, you do not want optimizationsenabled. As you near the end of your development cycle, though, the release build configuration can giveyou an indication of the size of your finished product, so the Fastest, Smallest option is appropriate.

Don’t Block the Main Thread 872011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 7

Tuning for Performance and Responsiveness

Page 88: MOSXAppProgrammingGuide

Table 7-1 lists the optimization levels available in Xcode. When you select one of these options, Xcode passesthe appropriate flags to the compiler for the given group or files. These options are available at the targetlevel or as part of a build configuration. See the Xcode Build System Guide for information on working withbuild settings for your project.

Table 7-1 Compiler optimization options

DescriptionXcode setting

The compiler does not attempt to optimize code. Use this option during developmentwhen you are focused on solving logic errors and need a fast compile time. Do not usethis option for shipping your executable.

None

The compiler performs simple optimizations to boost code performance while minimizingthe impact to compile time. This option also uses more memory during compilation.

Fast

The compiler performs nearly all supported optimizations that do not require a space-timetradeoff. The compiler does not perform loop unrolling or function inlining with thisoption. This option increases both compilation time and the performance of generatedcode.

Faster

The compiler performs all optimizations in an attempt to improve the speed of thegenerated code. This option can increase the size of generated code as the compilerperforms aggressive inlining of functions.

This option is generally not recommended.

Fastest

The compiler performs all optimizations that do not typically increase code size. This isthe preferred option for shipping code because it gives your executable a smaller memoryfootprint.

Fastest, Smallest

As with any performance enhancement, do not make assumptions about which option will give you the bestresults. You should always measure the results of each optimization you try. For example, the Fastest optionmight generate extremely fast code for a particular module, but it usually does so at the expense of executablesize. Any speed advantages you gain from the code generation are easily lost if the code needs to be pagedin from disk at runtime.

Use Core Data for Large Data Sets

If your application manipulates large amounts of structured data, store it in a Core Data persistent store orin a SQLite database instead of in a flat file. Both Core Data and SQLite provide efficient ways to managelarge data sets without requiring the entire set to be in memory all at once. Use SQLite if you deal withlow-level data structures, or an existing SQLite database. Core Data provides a high-level abstraction forefficient object-graph management with an Objective-C interface; it is, however, an advanced frameworkand you shouldn't use it until you have gained adequate experience.

For more information about Core Data, see Core Data Programming Guide and Optimizing Core Data withInstruments.

88 Decrease Your Application’s Code Size2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 7

Tuning for Performance and Responsiveness

Page 89: MOSXAppProgrammingGuide

Eliminate Memory Leaks

Your application should not have any memory leaks. You can use the Instruments application to track downleaks in your code, both in the simulator and on actual devices. See “Memory Instruments” in InstrumentsUser Guide for information about finding memory leaks.

Dead Strip Your Code

For statically linked executables, dead-code stripping is the process of removing unreferenced code fromthe executable file. If the code is unreferenced, it must not be used and therefore is not needed in theexecutable file. Removing dead code reduces the size of your executable and can help reduce paging.

To enable dead-code stripping in Xcode, in the Linking group of Build Settings, set the Dead Code Strippingoption to Yes.

Strip Symbol Information

Debugging symbols and dynamic-binding information can take up a lot of space and comprise a largepercentage of your executable’s size. Before shipping your code, you should strip out all unneeded symbols.

To strip debugging symbols from your executable, change the Xcode compiler code generation GenerateDebug Symbols option to No. You can also generate debugging symbols on a target-by-target basis if youprefer. See the Xcode Help for more information on build configurations and target settings.

Build Fixed-Position Application Code

Much code is built with an option that enables indirect symbol addressing and position-independent codegeneration, so that the generated code can be relocated within the virtual memory space of the process. Forprojects such as bundles and frameworks, this option is required. The dynamic-linker must be able to relocatethe bundle or framework and patch up symbol references at runtime.

Unlike bundles and frameworks, applications do not need position-independent code generation. Applicationcode is never relocated within the process space. You should always set the Generate Position-DependentCode option to Yes when building the Release version of your executable.

See Code Size PerformanceGuidelines for more detailed information about reducing the size of your executable.

Decrease Your Application’s Code Size 892011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 7

Tuning for Performance and Responsiveness

Page 90: MOSXAppProgrammingGuide

90 Decrease Your Application’s Code Size2011-06-27 | © 2011 Apple Inc. All Rights Reserved.

CHAPTER 7

Tuning for Performance and Responsiveness

Page 91: MOSXAppProgrammingGuide

This table describes the changes to Mac OS X App Programming Guide.

NotesDate

New document describing the development process for Mac OS X applications.2011-06-27

912011-06-27 | © 2011 Apple Inc. All Rights Reserved.

REVISION HISTORY

Document Revision History

Page 92: MOSXAppProgrammingGuide

922011-06-27 | © 2011 Apple Inc. All Rights Reserved.

REVISION HISTORY

Document Revision History