File System Programming Guide 17.9.2014
File System Programming Guide 17.9.2014
Programming Guide
Contents
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
2
Contents
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
3
Contents
Performance Tips 86
Things to Look For in Your Code 86
Use Modern File-System Interfaces 87
General Tips 87
The System Has Its Own File Caching Mechanism 88
Zero-Fill Delays Provide Security at a Cost 89
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
4
Contents
The Finder 94
Filename Sorting Rules 94
Presentation Rules for Files and Directories 94
File Types and Creator Codes 95
OS X File System Security 95
Security Schemes 96
Special Users And Groups 108
Network File Systems 110
iOS File System Security 112
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
5
Figures, Tables, and Listings
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
6
Figures, Tables, and Listings
Listing 7-2 Reading the bytes from a text file using a dispatch I/O channel 76
Listing 7-3 Reading the contents of a file using NSFileHandle 79
Listing 7-4 Reading the contents of a file using POSIX functions 81
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
7
About Files and Directories
Important: This is a preliminary document for an API or technology in development. Apple is supplying
this information to help you plan for the adoption of the technologies and programming interfaces described
herein for use on Apple-branded products. This information is subject to change, and software implemented
according to this document should be tested with final operating system software and final documentation.
Newer versions of this document may be provided with future betas of the API or technology.
The file system is an important part of any operating system. After all, it’s where users keep their stuff. The
organization of the file system plays an important role in helping the user find files. The organization also
makes it easier for apps and the system itself to find and access the resources they need to support the user.
This document is intended for developers who are writing software for OS X, iOS, and iCloud. It shows you
how to use the system interfaces to access files and directories and how to move files to and from iCloud. This
document also provides guidance on how best to work with files, and it shows you where you should be
placing any new files you create.
Important: When you adopt App Sandbox in your OS X app, the behavior of many file system features
changes. For example, to obtain access to locations outside of your app’s container directory, you must
request appropriate entitlements. To obtain persistent access to a file system resource, you must employ
the security-scoped bookmark features of the NSURL class or the CFURLRef opaque type. There are changes
to the location of app support files (which are relative to your container rather than to the user’s home
folder) and to the behavior of Open and Save dialogs (which are presented by the OS X security technology,
Powerbox, not AppKit). For details on all these changes, read App Sandbox Design Guide .
At a Glance
To effectively use the file system, know what to expect from the file system itself and which technologies are
available for accessing it.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
8
About Files and Directories
At a Glance
Relevant chapters and appendixes: File System Basics (page 11), OS X Library Directory Details (page
90), File System Details (page 93)
Relevant Chapter: The Role of File Coordinators and Presenters (page 43)
Relevant section: Choose the Right Way to Access Files (page 28)
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
9
About Files and Directories
See Also
Relevant chapter: Using the Open and Save Panels (page 57)
As you read and write files, you should also use file coordinators to ensure that any actions you take on a file
do not cause problems for other apps that care about the file.
Relevant chapter: Techniques for Reading and Writing Files Without File Coordinators (page 72)
See Also
For information about more advanced file-system tasks that you can perform, see File System Advanced
Programming Topics .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
10
File System Basics
The file systems in OS X and iOS handle the persistent storage of data files, apps, and the files associated with
the operating system itself. Therefore, the file system is one of the fundamental resources used by all processes.
The file systems in OS X and iOS are both based on the UNIX file system. All of the disks attached to the
computer—whether they are physically plugged into the computer or are connected indirectly through the
network—contribute space to create a single collection of files. Because the number of files can easily be many
millions, the file system uses directories to create a hierarchical organization. Although the basic directory
structures are similar for iOS and OS X, there are differences in the way each system organizes apps and user
data.
Before you begin writing code that interacts with the file system, you should first understand a little about the
organization of file system and the rules that apply to your code. Aside from the basic tenet that you cannot
write files to directories for which you do not have appropriate security privileges, apps are also expected to
be good citizens and put files in appropriate places. Precisely where you put files depends on the platform,
but the overarching goal is to make sure that the user’s files remain easily discoverable and that the files your
code uses internally are kept out of the user’s way.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
11
File System Basics
About the iOS File System
These containers constitute the app’s primary view of the file system. Figure 1-1 shows a representation of the
sandbox for an app.
Because it is in a sandbox, an app is generally prohibited from accessing or creating files outside its containers.
One exception to this rule occurs when an app uses public system interfaces to access things such as the user’s
contacts or music. In those cases, the system frameworks handle any file-related operations needed to read
from or modify the appropriate data stores.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
12
File System Basics
About the iOS File System
Directory Description
AppName .app This is the app’s bundle. This directory contains the app and all of its resources.
You cannot write to this directory. To prevent tampering, the bundle directory
is signed at installation time. Writing to this directory changes the signature
and prevents your app from launching. You can, however, gain read-only access
to any resources stored in the apps bundle. For more information, see the
Resource Programming Guide
The contents of this directory are not backed up by iTunes. However, iTunes
does perform an initial sync of any apps purchased from the App Store.
Documents/ Use this directory to store user-generated content. The contents of this directory
can be made available to the user through file sharing; therefore, his directory
should only contain files that you may wish to expose to the user.
The contents of this directory are backed up by iTunes.
Documents/Inbox Use this directory to access files that your app was asked to open by outside
entities. Specifically, the Mail program places email attachments associated
with your app in this directory. Document interaction controllers may also place
files in it.
Your app can read and delete files in this directory but cannot create new files
or write to existing files. If the user tries to edit a file in this directory, your app
must silently move it out of the directory before making any changes.
The contents of this directory are backed up by iTunes.
Library/ This is the top-level directory for any files that are not user data files. You
typically put files in one of several standard subdirectories. iOS apps commonly
use the Application Support and Caches subdirectories; however, you
can create custom subdirectories.
Use the Library subdirectories for any files you don’t want exposed to the
user. Your app should not use these directories for user data files.
The contents of the Library directory (with the exception of the Caches
subdirectory) are backed up by iTunes.
For additional information about the Library directory and its commonly used
subdirectories, see The Library Directory Stores App-Specific Files (page 21).
tmp/ Use this directory to write temporary files that do not need to persist between
launches of your app. Your app should remove files from this directory when
they are no longer needed; however, the system may purge this directory when
your app is not running.
The contents of this directory are not backed up by iTunes.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
13
File System Basics
About the iOS File System
An iOS app may create additional directories in the Documents, Library, and tmp directories. You might do
this to better organize the files in those locations.
For information about how to get references to the preceding directories from your iOS app, see Locating
Items in the Standard Directories (page 33). For tips on where to put files, see Where You Should Put Your
App’s Files (page 14).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
14
File System Basics
About the OS X File System
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
15
File System Basics
About the OS X File System
Figure 1-2 shows how the local, system, and user domains map to the local file system of an OS X installation.
(The network domain is not shown but is similar in many ways to the local domain.) This figure shows the
visible directories that the user might see. Depending on the user’s system, other directories may be visible or
some of the ones shown here may be hidden.
For information about the contents of the directories in OS X, see OS X Standard Directories: Where Files
Reside (page 17). For information about the directories that OS X normally hides from the user (and why), see
Hidden Files and Directories: Simplifying the User Experience (page 19).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
16
File System Basics
About the OS X File System
Directory Usage
/Applications This directory is where you install apps intended for use by all users of a computer.
The App Store installs apps purchased by the user in this directory automatically.
The Utilities subdirectory contains a subset of apps that are intended for use
in managing the local system.
This directory is part of the local domain.
Library There are multiple Library directories on the system, each one associated with
a different domain or specific user. Apps should use the Library directory to
store app-specific (or system-specific) resources.
For detailed information about the contents of this directory and how you use it
to support your apps, see The Library Directory Stores App-Specific Files (page
21).
/Network This directory contains the list of computers in the local area network.
There is no guarantee that files located on network file servers will have the
/Network directory at the beginning of their path. Path names vary depending
on several factors, including how the network volume was mounted. For example,
if the user uses the Connect to Server command to mount a volume, paths begin
with the /Volumes directory. When writing code, assume that files on any volume
other than the boot volume could be located on a network-based server.
/System This directory contains the system resources required by OS X to run. These
resources are provided by Apple and must not be modified.
This directory comprises the contents of the system domain.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
17
File System Basics
About the OS X File System
Directory Usage
/Users This directory contains one or more user home directories. The user home directory
is where user-related files are stored. A typical user’s home directory includes the
following subdirectories:
Applications—Contains user-specific apps.
Sites—Contains web pages used by the user’s personal site. (Web Sharing
must be enabled to display these pages.)
The preceding directories are for storing user documents and media only. Apps
must not write files to the preceding directories unless explicitly directed to do
so by the user. The sole exception to this rule is the Library directory, which
apps may use to store data files needed to support the current user.
Of the subdirectories, only the Public directory is accessible by other users on
the system. Access to the other directories is restricted by default.
Important: The files in the user’s Documents and Desktop directories should reflect only the documents
that the user created and works with directly. Similarly, the media directories should contain only the user’s
media files. Those directories must never be used to store data files that your app creates and manages
automatically. If you need a place to store automatically generated files, use the Library directory, which
is designated specifically for that purpose. For information on where to put files in the Library directory,
see The Library Directory Stores App-Specific Files (page 21).
Although the directories in Table 1-2 (page 17) are the ones seen by OS X users, they are not the only directories
present in the file system. OS X hides many directories to prevent users from accessing files that they don’t
need to.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
18
File System Basics
About the OS X File System
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
19
File System Basics
About the OS X File System
● Packages and bundles. Packages and bundles are directories that the Finder presents to the user as if
they were files. Bundles hide the internal workings of executables such as apps and just present a single
entity that can be moved around the file system easily. Similarly, packages allow apps to implement
complex document formats consisting of multiple individual files while still presenting what appears to
be a single document to the user.
Although the Finder and other system interfaces hide files and directories from the user, Cocoa interfaces such
as NSFileManager do not filter out files or directories that are normally invisible to users. Thus, code that
uses these interfaces theoretically has a complete view of the file system and its contents. (Of course, a process
really has access to only those files and directories for which it has appropriate permissions.)
Display names do not affect the actual name of the file in the file system. Code that accesses a file or directory
programmatically must specify the item’s actual name when opening or manipulating the item using the file
system interfaces. The only time your app should ever use display names is when displaying the name of a file
or directory to the user. You can get the display name for any file or directory using the displayNameAtPath:
method of NSFileManager.
Important: Your code should not allow users to modify display names directly. When you want the user
to specify the name of a file, use a Save panel.
For information on how to localize the directories your app creates, see File System Advanced Programming
Topics . For more information about localizing app content, see Internationalization and Localization Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
20
File System Basics
About the OS X File System
There are several Library directories throughout the system but only a few that your code should ever need
to access:
● Library in the current home directory—This is the version of the directory you use the most because it
is the one that contains all user-specific files. In iOS, Library is placed inside the apps data bundle. In OS
X, it is the app’s sandbox directory or the current user’s home directory (if the app is not in a sandbox).
● /Library (OS X only)—Apps that share resources between users store those resources in this version of
the Library directory. Sandboxed apps are not permitted to use this directory.
● /System/Library (OS X only)—This directory is reserved for use by Apple.
After selecting which version of the Library directory to use, you still need to know where to store your files.
The Library directory itself contains several subdirectories that subdivide app-specific content into a few
well-known categories. Table 1-3 lists the most common subdirectories that you might use. Although Library
directories in OS X contain many more subdirectories than the ones listed, most are used only by the system.
If you want a more complete list of subdirectories, though, see OS X Library Directory Details (page 90).
Directory Usage
Application Use this directory to store all app data files except those associated with the user’s
Support documents. For example, you might use this directory to store app-created data files,
configuration files, templates, or other fixed or modifiable resources that are managed
by the app. An app might use this directory to store a modifiable copy of resources
contained initially in the app’s bundle. A game might use this directory to store new
levels purchased by the user and downloaded from a server.
All content in this directory should be placed in a custom subdirectory whose name
is that of your app’s bundle identifier or your company.
In iOS, the contents of this directory are backed up by iTunes.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
21
File System Basics
The iCloud File Storage Container
Directory Usage
Caches Use this directory to write any app-specific support files that your app can re-create
easily. Your app is generally responsible for managing the contents of this directory
and for adding and deleting files as needed.
In iOS 2.2 and later, the contents of this directory are not backed up by iTunes. In
addition, iTunes removes files in this directory during a full restoration of the device.
On iOS 5.0 and later, the system may delete the Caches directory on rare occasions
when the system is very low on disk space. This will never occur while an app is
running. However, you should be aware that iTunes restore is not necessarily the
only condition under which the Caches directory can be erased.
Frameworks In OS X, frameworks that must be shared by multiple apps can be installed in either
the local or user domain. The Frameworks directory in the system domain stores the
frameworks you use to create your OS X apps.
In iOS, apps cannot install custom frameworks.
Preferences This directory contains app-specific preference files. You should not create files in
this directory yourself. Instead, use the NSUserDefaults class or CFPreferences API
to get and set preference values for your app.
In iOS, the contents of this directory are backed up by iTunes.
Documents that the user creates and sees in an app's user interface—for example the document browsers in
Pages, Numbers, and Keynote should be stored in the Documents directory. Another example of files that
might go in the Documents directory are saved games, again because they are something that an app could
potentially provide some sort of method for selecting.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
22
File System Basics
How the System Identifies the Type of Content in a File
Anything that the app does not want the user to see or modify directly should be placed outside of the
Documents directory. Apps can create any subdirectories inside the container directory, so they can arrange
private files as desired.
Apps create files and directories in iCloud container directories in exactly the same way as they create local
files and directories. And all the file’s attributes are saved, if they add extended attributes to a file, those
attributes are copied to iCloud and to the user's other devices too.
iCloud containers also allow the storage of key-value pairs that can be easily accessed without having to create
a document format.
A uniform type identifier is a string that uniquely identifies a class of entities considered to have a “type.”
UTIs provide consistent identifiers for data that all apps and services can recognize and rely upon. They are
also more flexible than most other techniques because you can use them to represent any type of data, not
just files and directories. Examples of UTIs include:
public.text—A public type that identifies text data.
Whenever a UTI-based interface is available for specifying file types, you should prefer that interface over any
others. Many OS X interfaces allow you to specify UTIs corresponding to the files or directories you want to
work with. For example, in the Open panel, you can use UTIs as file filters and limit the types of files the user
selects to ones your app can handle. Several AppKit classes, including NSDocument, NSPasteboard, and
NSImage, support UTIs. In iOS, UTIs are used to specify pasteboard types only.
One way the system determines the UTI for a given file is by looking at its filename extension. A filename
extension is a string of characters appended to the end of a file and separated from the main filename with
a period. Each unique string of characters identifies a file of a specific type. For example, the .strings extension
identifies a resource file with localizable string data while the .png extension identifies a file with image data
in the portable network graphics format.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
23
File System Basics
Security: Protect the Files You Create
Note: Because period characters are valid characters in OS X and iOS filenames, only the characters
after the last period in a filename are considered part of the filename extension. Everything to the
left of the last period is considered part of the filename itself.
If your app defines custom file formats, you should register those formats and any associated filename extensions
in your app’s Info.plist file. The CFBundleDocumentTypes key specifies the file formats that your app
recognizes and is able to open. Entries for any custom file formats should include both a filename extension
and UTI corresponding to the file contents. The system uses that information to direct files with the appropriate
type to your app.
For more information about UTIs and how you use them, see Uniform Type Identifiers Overview . For more
information about the CFBundleDocumentTypes key, see Information Property List Key Reference .
For general information about secure coding practices when working with files, see Secure Coding Guide .
Developers writing apps for OS X v10.7 and later are encouraged to put their apps in sandboxes to enhance
security. Developers of iOS apps do not have to explicitly put their app in a sandbox because the system does
it for them automatically at install time.
For more information about sandboxes and the types of restrictions they impose on file system access, see
Mac App Programming Guide and App Sandbox Design Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
24
File System Basics
Security: Protect the Files You Create
Note: For a file on a network server, do not make any assumptions about the ACLs and BSD
permissions associated with the file. Some network file systems provide only a summarized version
of this information.
Because iOS apps always run in a sandbox, the system assigns specific ACLs and permissions to files created
by each app. However, OS X apps can use Identity Services to manage access control lists for files to which
they have access. For information about how to use Identity Services (and the Collaboration framework), see
Identity Services Programming Guide .
In iOS, apps that take advantage of disk-based encryption need to be discontinue the use of encrypted files
when the user locks the device. Because locking the device destroys the decryption keys, access to encrypted
files is limited to when the device is unlocked. If your iOS app can run in the background while the device is
locked, it must do so without access to any of its encrypted files. Because encrypted disks in OS X are always
accessible while the computer is running, OS X apps do not need to do anything special to handle disk-level
encryption.
For more information about working with encrypted files in iOS, see App Programming Guide for iOS .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
25
File System Basics
Synchronization Ensures Robustness in Your File-Related Code
File system synchronization is primarily an issue in OS X, where the user can manipulate files directly with the
Finder or with any number of other apps at the same time. Fortunately, OS X provides the following interfaces
to help with synchronization issues:
● File coordinators. In OS X v10.7 and later, file coordinators are a way to incorporate fine-grained
synchronization support directly into the objects of your app; see The Role of File Coordinators and
Presenters (page 43).
● FSEvents. In OS X v10.5 and later, file system events allow you to monitor changes to a directory or its
contents; see File System Events Programming Guide .
Class/Technology Notes
NSFileManager For most tasks, it is safe to use the default NSFileManager object
simultaneously from multiple background threads. The only exception to
this rule is tasks that interact with the file manager’s delegate. When using
a file manager object with a delegate, it is recommended that you create a
unique instance of the NSFileManager class and use your delegate with
that instance. You should then use your unique instance from one thread
at a time.
Grand Central Dispatch GCD itself is safe to use from any thread. However, you are still responsible
for writing your blocks in a way that is thread safe.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
26
File System Basics
Files, Concurrency, and Thread Safety
Class/Technology Notes
NSFileHandle, Most of the Foundation objects you use to read and write file data can be
NSData, Cocoa streams used from any single thread but should not be used from multiple threads
simultaneously.
Open and Save panels Because they are part of your user interface, you should always present and
manipulate the Open and Save panels from your app’s main thread.
POSIX routines The POSIX routines for manipulating files are generally designed to operate
safely from any thread. For details, see the corresponding man pages.
NSURL and NSString The immutable objects you use to specify paths are safe to use from any
thread. Because they are immutable, you can also refer to them from multiple
threads simultaneously. Of course, the mutable versions of these objects
should be used from only one thread at a time.
NSEnumerator and its Enumerator objects are safe to use from any single thread but should not
subclasses be used from multiple threads simultaneously.
Even if you use an thread-safe interface for manipulating a file, problems can still arise when multiple threads
or multiple processes attempt to act on the same file. Although there are safeguards to prevent multiple clients
from modifying a file at the same time, those safeguards do not always guarantee exclusive access to the file
at all times. (Nor should you attempt to prevent other processes from accessing shared files.) To make sure
your code knows about changes made to shared files, use file coordinators to manage access to those files.
For more information about file coordinators, see The Role of File Coordinators and Presenters (page 43)
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
27
Accessing Files and Directories
Before you can open a file, you first have to locate it in the file system. The system frameworks provide many
routines for obtaining references to many well-known directories, such as the Library directory and its
contents. You can also specify locations manually by building a URL or string-based path from known directory
names.
When you know the location of a file, you can then start planning the best way to access it. Depending on the
type of file, you may have several options. For known file types, you typically use built-in system routines to
read or write the file contents and give you an object that you can use. For custom file types, you may need
to read the raw file data yourself.
Resource Nib files Apps use resource files to store data that is independent of the
files Image files code that uses it. Resource files are commonly used to store
localizable content such as strings and images. The process for
Sound files reading data from a resource file depends on the resource type.
Strings files For information about how to read the contents of resource
Localized resources files, see Resource Programming Guide .
Text files Plain text file A text file is an unstructured sequence of ASCII or Unicode
UTF-8 formatted file characters. You typically load the contents of a text file into an
NSString object but may also read and write a text file as a
UTF-16 formatted raw stream of characters.
file
For information about using the NSString class to load text
from a file, see String Programming Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
28
Accessing Files and Directories
Choose the Right Way to Access Files
Structured XML file A structured data file usually consists of string-based data
data files Property list file arranged using a set of special characters.
Preference file For information about parsing XML, see Event-Driven XML
Programming Guide .
Archive Binary files created An archive is a file format used to store a persistent version of
files using a keyed your app’s runtime objects. An archiver object encodes the
archiver object state of the objects into a stream of bytes that can be written
to disk all at once. An unarchiver reverses the process, using
the stream of bytes to re-create the objects and restore them
to their previous state.
Archives are often a convenient alternative to implementing
custom binary file formats for your documents or other data
files.
For information on how to create and read archive files, see
Archives and Serializations Programming Guide .
File Custom document A file package is a directory that contains any number of custom
packages formats data files but which is presented to the user as if it were a single
file. Apps can use file packages to implement complex file
formats that contain multiple distinct files, or a mixture of
different types of files. For example, you might use a file package
if your file format includes both a binary data file and one or
more image, video, or audio files. You access the contents of a
file package using NSFileWrapper objects.
Bundles Apps Bundles provide a structured environment for storing code and
Plug-ins the resources used by that code. Most of the time, you do not
work with the bundle itself but with its contents. However, you
Frameworks can locate bundles and obtain information about them as
needed.
For information about bundles and how you access them, see
Bundle Programming Guide
Code files Binary code Apps that work with plug-ins and shared libraries need to be
resources able to load the associated code for that item to take advantage
Dynamic shared of its functionality.
libraries For information about how to load code resources into memory,
see Code Loading Programming Topics .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
29
Accessing Files and Directories
Specifying the Path to a File or Directory
A file A collection of files Apps use file wrappers to store files in a manner that can be
wrapper that appear as a written in a serialized manner that can use used with the
single file pasteboard or stored as part of your data record. See Using
FileWrappers as File Containers (page 83) for more information
on file wrappers.
In situations where the standard file formats are insufficient, you can always create your own custom file
formats. When reading and writing the content of custom files, you read and write data as a stream of bytes
and apply those bytes to your app’s file-related data structures. You have complete control over how you read
and write the bytes and how you manage your file-related data structures. For more information about the
techniques for reading and writing files that use custom file formats, see Techniques for Reading and Writing
Files Without File Coordinators (page 72).
Note: In addition to NSURL, you can also use the CFURLRef opaque type to manipulate paths as
URLs. The NSURL class is toll-free bridged with the CFURLRef type, which means you can use them
interchangeably in your code. For more information about how to create and manipulate URLs using
Core Foundation, see CFURL Reference .
For most URLs, you build the URL by concatenating directory and file names together using the appropriate
NSURL methods until you have the path to the item. A URL built in that way is referred to as a path-based URL
because it stores the names needed to traverse the directory hierarchy to locate the item. (You also build
string-based paths by concatenating directory and file-names together, with the results stored in a slightly
different format than that used by the NSURL class.) In addition to path-based URLs, you can also create a file
reference URL, which identifies the location of the file or directory using a unique ID.
All of the following entries are valid references to a file called MyFile.txt in a user’s Documents directory:
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
30
Accessing Files and Directories
Locating Items in the File System
Different file systems rely on different separator characters. Because of these changes, you should create your
URL objects using the methods provided by the NSURL class.
You create URL objects using the NSURL methods and convert them to file reference URLs only when needed.
Path-based URLs are easier to manipulate, easier to debug, and are generally preferred by classes such as
NSFileManager. An advantage of file reference URLs is that they are less fragile than path-based URLs while
your app is running. If the user moves a file in the Finder, any path-based URLs that refer to the file immediately
become invalid and must be updated to the new path. However, as long as the file moved to another location
on the same disk, its unique ID does not change and any file reference URLs remain valid.
Important: Although they are safe to use while your app is running, file reference URLs are not safe to
store and reuse between launches of your app because a file’s ID may change if the system is rebooted. If
you want to store the location of a file persistently between launches of your app, create a bookmark as
described in Locating Files Using Bookmarks.
Of course, there are still times when you might need to use strings to refer to a file. Fortunately, the NSURL
class provides methods to convert path-based URLs to and from NSString objects. You might use a string-based
path when presenting that path to the user or when calling a system routine that accepts strings instead of
URLs. The conversion between NSURL objects and NSString objects is done using the NSURL class’s method
absoluteString.
Because NSURL and NSString describe only the location of a file or directory, you can create them before the
actual file or directory exists. Neither class attempts to validate the actual existence of the file or directory you
specify. In fact, you must create the path to a nonexistent file or directory before you can create it on disk.
For more information about the methods you use to create and manipulate URLs and strings, see NSURL Class
Reference and NSString Class Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
31
Accessing Files and Directories
Locating Items in the File System
The file systems of iOS and OS X impose specific guidelines on where you should place files, so most of the
items your app creates or uses should be stored in a well-known place. Both systems provide interfaces for
locating items in such well-known places, and your app can use these interfaces to locate items and build
paths to specific files. An app should prompt the user to specify the location of a file or directory only in a
limited number of situations that are described in Using the Open and Save Panels (page 57).
You should never use the Open and Save panels to access any files that your app created and uses internally.
Support files, caches, and app-generated data files should be placed in one of the standard directories dedicated
to app-specific files.
For information on how to present and customize the Open and Save panels, see Using the Open and Save
Panels (page 57).
The following code shows how to retrieve a URL object for an image named MyImage.png that is located in
the app’s main bundle. This code determines only the location of the file; it does not open the file. You would
pass the returned URL to a method of the NSImage class to load the image from disk so that you could use it.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
32
Accessing Files and Directories
Locating Items in the File System
For more information about bundles, including how to locate items in a bundle, see Bundle Programming
Guide . For specific information about loading and using resources in your app, see Resource Programming
Guide .
You can use the URL or path-based string you receive from the preceding routines to build new objects with
the locations of the files you want. Both the NSURL and NSString classes provide path-related methods for
adding and removing path components and making changes to the path in general. Listing 2-1 shows an
example that searches for the standard Application Support directory and creates a new URL for a directory
containing the app’s data files.
Listing 2-1 Creating a URL for an item in the app support directory
- (NSURL*)applicationDataDirectory {
inDomains:NSUserDomainMask];
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
33
Accessing Files and Directories
Locating Items in the File System
if (appSupportDir) {
return appDirectory;
- (NSData*)bookmarkForURL:(NSURL*)url {
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&theError];
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
34
Accessing Files and Directories
Locating Items in the File System
return nil;
return bookmark;
If you write the persistent bookmark data to disk using the writeBookmarkData:toURL:options:error:
method of NSURL, what the system creates on disk is an alias file. Aliases are similar to symbolic links but are
implemented differently. Normally, users create aliases from the Finder when they want to create links to files
elsewhere on the system.
- (NSURL*)urlForBookmark:(NSData*)bookmark {
options:NSURLBookmarkResolutionWithoutUI
relativeToURL:nil
bookmarkDataIsStale:&bookmarkIsStale
error:&theError];
return nil;
return bookmarkURL;
The Core Foundation framework provides a set of C-based functions that parallel the bookmark interface
provided by NSURL. For more information about using those functions, see CFURL Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
35
Accessing Files and Directories
Enumerating the Contents of a Directory
Enumerator objects return the paths of all files and directories contained within the enumerated directory.
Because enumerations are recursive and cross device boundaries, the number of files and directories returned
may be more than what is present in the starting directory. You can skip the contents of any directory you are
not interested in by calling the enumerator object’s skipDescendents method. Enumerator objects do not
resolve symbolic links or attempt to traverse symbolic links that point to directories.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
36
Accessing Files and Directories
Enumerating the Contents of a Directory
enumeratorAtURL:directoryURL
includingPropertiesForKeys:keys
options:(NSDirectoryEnumerationSkipsPackageDescendants |
NSDirectoryEnumerationSkipsHiddenFiles)
}];
if ([isDirectory boolValue]) {
if ([isPackage boolValue]) {
else {
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
37
Accessing Files and Directories
Enumerating the Contents of a Directory
You can use other methods declared by NSDirectoryEnumerator to determine attributes of files during
the enumeration—both of the parent directory and the current file or directory—and to control recursion into
subdirectories. The code in Listing 2-5 enumerates the contents of a directory and lists files that have been
modified within the last 24 hours; if, however, it comes across RTFD file packages, it skips recursion into them.
Listing 2-5 Looking for files that have been modified recently
[directoryEnumerator skipDescendents];
else {
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
38
Accessing Files and Directories
Determining Where to Store Your App-Specific Files
There are two options for doing a batch enumeration of a directory using NSFileManager:
● To perform a shallow enumeration, use the
contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error: or
contentsOfDirectoryAtPath:error: method.
● To perform a deep enumeration and return only subdirectories, use the
subpathsOfDirectoryAtPath:error: method.
NSURLCreationDateKey, NSURLLocalizedTypeDescriptionKey,
nil];
contentsOfDirectoryAtURL:url
includingPropertiesForKeys:properties
options:(NSDirectoryEnumerationSkipsHiddenFiles)
error:&error];
if (array == nil) {
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
39
Accessing Files and Directories
Tips for Accessing Files and Directories
Note: Apps rarely share the files stored in the Application Support, Caches or Temp directories.
Therefore, you don’t typically need to use a file coordinator (NSFileCoordinator) when reading
or writing to these locations. For more information about file coordination, see The Role of File
Coordinators and Presenters (page 43).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
40
Accessing Files and Directories
Tips for Accessing Files and Directories
● Write data to disk only when you have something valuable to save. The definition of what is valuable
is different for each app but should generally involve information that the user provides explicitly. For
example, if your app creates some default data structures at launch time, you should not save those
structures to disk unless the user changes them.
● Read data from disk only when you need it. In other words, load data that you need for your user interface
now but do not load an entire file just to get one small piece of data from that file. For custom file formats,
use file mapping or read only the few chunks of a file that you need to present your user interface. Read
any remaining chunks as needed in response to user interactions with the data. For structured data formats,
use Core Data to manage and optimize the reading of data for you.
For additional tips and coding practices, see Race Conditions and Secure File Operations in Secure Coding
Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
41
Accessing Files and Directories
Tips for Accessing Files and Directories
For more information about display names, see Files and Directories Can Have Alternate Names (page 20).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
42
The Role of File Coordinators and Presenters
Because the file system is shared by all running processes, problems can occur when two processes (or two
threads in the same process) try to act on the same file at the same time. Two different processes acting on
the same file might make changes that the other is not expecting, which could lead to more serious problems
like crashes or data corruption. And even within a single program, two threads acting on the file simultaneously
can corrupt it and render it unusable. To avoid this type of file contention, OS X v10.7 and later includes support
for file coordinators, which allow you to coordinate file access safely between different processes or different
threads.
The job of a file coordinator is to notify interested parties whenever a file they care about is acted on by another
process or thread. The interested parties in this case are the objects of your app. Any object of your app can
designate itself as a file presenter—that is, an object that works directly with a file and needs to be notified
when actions are initiated on that file by other objects. Any object in your app can be a file presenter and a
file presenter can monitor individual files or whole directories of files. For example, an app that works with
images would designate one or more objects as file presenters for the corresponding image files. If the user
deleted an image file from the Finder while the app was running, the file presenter for that image file would
be notified and given an opportunity to accommodate the deletion of the file.
Whenever possible you should explore using these classes to store your user data. Your app need only work
directly with file coordinators and file presenters when dealing with files other than the user’s data files.
Apps that use the document classes don’t need to use file coordinators when the app reads and writes private
files in the Application Support, Cache, or temporary directories. These files are considered private.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
43
The Role of File Coordinators and Presenters
Ensuring Safe Read and Write Operations Using File Coordinators
The steps for adding support for file coordinators to your code is as follows:
1. For each object that manages a file or directory, make the corresponding class adopt the NSFilePresenter
protocol. The system uses the methods of this protocol to notify your object when changes occur to the
monitored file.
2. When you initialize your file presenter object at runtime, register it immediately by calling the
addFilePresenter: class method of NSFileCoordinator.
3. When your file presenter object performs its own actions on a file or directory, create an
NSFileCoordinator object and call the method that corresponds to the action you plan to take.
4. In the dealloc method of your file presenter object, call the removeFilePresenter: class method of
NSFileCoordinator to unregister it as a file presenter.
You generally do not need to monitor the files in your app bundle or any files that are private to your app and
stored in app-specific subdirectories of the ~/Library directory. If your app runs in a sandbox, you also do
not need to monitor any files you create inside your sandbox directory.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
44
The Role of File Coordinators and Presenters
Ensuring Safe Read and Write Operations Using File Coordinators
To implement a file presenter object, make the class for that object conform to the NSFilePresenterprotocol.
The methods in this protocol indicate the types of operations that can be performed on the file or directory.
Your implementation of the various methods is where your object responds and takes any necessary actions.
You do not have to implement every method of the protocol but should implement all methods that might
affect how your object interacts with the file or directory. You use the properties and methods of the protocol
to do the following:
● Provide the URL of the file or directory being monitored. (All file presenters must do this by implementing
the presentedItemURL property.)
● Relinquish control of the file or directory temporarily so that another object can write to it or read from
it.
● Save any unsaved changes before another object tries to read from the file.
● Track changes to the contents or attributes of a file or directory.
● Update your data structures when the file or directory is moved or deleted.
● Provide a dispatch queue on which to execute your file presenter methods.
If you are implementing a document-based app, you do not need to incorporate file presenter semantics into
your NSDocument subclasses. The NSDocument class already conforms to the NSFilePresenter protocol
and implements the appropriate methods. Thus, all of your documents automatically register themselves as
presenters of their corresponding file and do things like save changes and track changes to the document.
All of your file presenter methods should be lightweight and execute quickly. In cases where your file presenter
is responding to changes (such as in the presentedItemDidChange, presentedItemDidMoveToURL:, or
accommodatePresentedItemDeletionWithCompletionHandler: methods), you might want to avoid
incorporating changes directly from your file presenter method. Instead, dispatch a block asynchronously to
a dispatch queue and process the changes at a later time. This lets you process the changes at your app’s
convenience without causing unnecessary delays to the file coordinator that initiated the change. Of course,
when saving or relinquishing control of a file (such as in the relinquishPresentedItemToReader:,
relinquishPresentedItemToWriter:, or savePresentedItemChangesWithCompletionHandler:
methods) you should perform all necessary actions immediately and not defer them.
For details about how to implement the methods of the NSFilePresenter protocol, see NSFilePresenter
Protocol Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
45
The Role of File Coordinators and Presenters
Ensuring Safe Read and Write Operations Using File Coordinators
Any object you register as a file presenter must also be unregistered using the removeFilePresenter:
method at appropriate times. Specifically, if you release a file presenter object in your code, you must unregister
it before it is actually deallocated. Failure to do this is a programmer error.
For more information about how to use the methods of NSFileCoordinator, see NSFileCoordinator Class
Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
46
iCloud File Management
Use the iCloud Storage APIs to write user documents and data to a central location and access those items
from all of a user’s computers and iOS devices. Making a user’s documents ubiquitous using iCloud means that
a user can view or edit those documents from any device without having to sync or transfer files explicitly.
Storing documents in a user’s iCloud account also provides a layer of security for that user. Even if a user loses
a device, the documents on that device are not lost if they are in iCloud storage.
Important: The iCloud APIs do not work with garbage collection in OS X. If your existing code uses garbage
collection, update your code to use ARC instead.
While in iCloud storage, changes made on one device are stored locally and then pushed to iCloud using a
local daemon, as shown in Figure 4-1. To prevent large numbers of conflicting changes from occurring at the
same time, apps are expected to use file coordinator objects to perform all changes. File coordinators mediate
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
47
iCloud File Management
Storing and Using Documents in iCloud
changes between your app and the daemon that facilitates the transfer of the document to and from iCloud.
In this way, the file coordinator acts like a locking mechanism for the document, preventing your app and the
daemon from modifying the document simultaneously.
From an implementation perspective, the easiest way to manage documents in iCloud is to use the NSDocument
class. This class does most of the heavy lifting required to read and write files that are stored in iCloud.
Specifically, the NSDocument class handles the creation and use of file coordinators to modify the document.
This class also seamlessly integrates document changes coming from other devices. The class even helps handle
the potential conflicts that can arise when two devices do manage to update the same file in conflicting ways.
You are not required to use the NSDocument class to manage your app’s documents, but using it requires less
effort on your part.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
48
iCloud File Management
iCloud Storage APIs
Doc
The sections that follow provide more details about how to implement different aspects of iCloud storage for
your app. For additional information about using specific classes and interfaces, see the corresponding reference
documentation.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
49
iCloud File Management
Working with Documents in iCloud
At the heart of the iCloud locking mechanism are file coordinators and file presenters. Whenever you need to
read and write a file, you do so using a file coordinator, which is an instance of the NSFileCoordinator
class. The job of a file coordinator is to coordinate the reads and writes performed by your app and the sync
daemon on the same document. For example, your app and the daemon may both read the document at the
same time but only one may write to the file at any single time. Also, if one process is reading the document,
the other process is prevented from writing to the document until the reader is finished.
In addition to coordinating operations, file coordinators also work with file presenters to notify apps when
changes are about to occur. A file presenter is any object that conforms to the NSFilePresenter protocol
and takes responsibility for managing a specific file (or directory of files) in an app. The job of a file presenter
is to protect the integrity of its own data structures. It does this by listening for messages from other file
coordinators and using those messages to update its internal data structures. In most cases, a file presenter
may not have to do anything. However, if a file coordinator declares that it is about to move a file to a new
URL, the file presenter would need to replace its old URL with the new one provided to it by the file coordinator.
The NSDocument class is an example of a file presenter that tracks changes to its underlying file or file package.
Here is a checklist of the things your app must do to work with documents in iCloud:
● Manage each document in iCloud using a file presenter. The recommended way to do this is to use the
NSDocument class, but you may define custom file presenters if you prefer. You can use a single file
presenter to manage a file package or a directory of files.
● After creating a file presenter, register it by calling the addFilePresenter: class method of
NSFileCoordinator. Registration is essential. The system can notify only registered presenter objects.
● Before deleting a file presenter, unregister it by calling the removeFilePresenter: method of
NSFileCoordinator.
All file-related operations must be performed through a file coordinator object. To read or write a document,
or move or delete it, follow these steps:
1. Create an instance of the NSFileCoordinator class and initialize it with the file presenter object that is
about to perform the file operation.
2. Use the methods of the NSFileCoordinator object to read or write the file:
● To read all or part of a single file, use the
coordinateReadingItemAtURL:options:error:byAccessor: method
● To write to a file or delete it, call the
coordinateWritingItemAtURL:options:error:byAccessor: method.
● To perform a sequence of read or write operations, use the
coordinateReadingItemAtURL:options:writingItemAtURL:options:error:byAccessor:
method.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
50
iCloud File Management
Moving a Document to iCloud Storage
For more information about using file coordinators and file presenters, see The Role of File Coordinators and
Presenters (page 43).
Warning: When working with iCloud files and directories, use the alphanumeric character set as much
as possible and avoid special punctuation or other special characters. You should assume that filenames
are case sensitive and should not change the letter case of any file. Always access the files using the
same letter case as the original file. Keeping your filenames simple helps ensure that those files can
be handled correctly on different types of file systems.
When moving documents to iCloud, you can create additional subdirectories inside the container directory to
manage your files. It is strongly recommended that you create a Documents subdirectory and use that directory
for storing user documents. In iCloud, the contents of the Documents directory are made visible to the user
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
51
iCloud File Management
Searching for Documents in iCloud
so that individual documents can be deleted. Everything outside of the Documents directory is grouped
together and treated as a single entity that a user can keep or delete. You create subdirectories in a user’s
iCloud storage using the methods of the NSFileManager class just as you would any directory.
After you move a document to iCloud, it is not necessary to save a URL to the document’s location persistently.
If you manage a document using a NSDocument object, that object automatically updates its local data
structures with the document’s new URL. However, it does not save that URL to disk, and neither should your
custom file presenters. Instead, because documents can move while in a user’s iCloud storage, you should use
an NSMetadataQuery object to search for documents. Searching guarantees that your app has the correct
URL for accessing the document. For information on how to search for documents in iCloud, see iCloud Storage
APIs.
For more information about the methods of the NSFileManager class, see NSFileManager Class Reference .
The NSMetadataQuery class supports the following search scopes for your documents:
● Use the NSMetadataQueryUbiquitousDocumentsScope constant to search for documents in iCloud
that reside somewhere inside a Documents directory. (For any given container directory, put documents
that the user is allowed to access inside a Documents subdirectory.)
● Use the NSMetadataQueryUbiquitousDataScope constant to search for documents in iCloud that
reside anywhere other than in a Documents directory. (For any given container directory, use this scope
to store user-related data files that your app needs to share but that are not files you want the user to
manipulate directly.)
To use a metadata query object to search for documents, create a new NSMetadataQuery object and do the
following:
1. Set the search scope of the query to an appropriate value (or values). It’s important to note that it is not
possible to combine local file system searches with iCloud searches. The search must be run separately.
2. Add a predicate to narrow the search results. For example, to search for all files, specify a predicate with
the format NSMetadataItemFSNameKey == *.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
52
iCloud File Management
Working with File Wrappers
3. Register for the query notifications and configure any other query parameters you care about, such as sort
descriptors, notification intervals, and so on.
The NSMetadataQuery object uses notifications to deliver query results. At a minimum, you should
register for the NSMetadataQueryDidUpdateNotification notification, but you might want to register
for others in order to detect the beginning and end of the results-gathering process.
4. Call the startQuery method of the query object.
5. Run the current run loop so that the query object can generate the results.
If you started the query on your app’s main thread, simply return and let the main thread continue
processing events. If you started the query on a secondary thread, you must configure and execute a run
loop explicitly. For more information about executing run loops, see Threading Programming Guide .
6. Process the results in your notification-handler methods.
When processing results, always disable updates first. Doing so prevents the query object from modifying
the result list while you are using it. When you are done processing the results, reenable updates again
to allow new updates to arrive.
7. When you are ready to stop the search, call the stopQuery method of the query object.
For more information on how to create and run metadata queries, see File Metadata Search Programming
Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
53
iCloud File Management
Handling File-Version Conflicts
To ensure that your file wrapper is treated as a single package, your app must export a properly formatted UTI
for your package. Specifically, you must specify that the UTI conforms to com.apple.package, and you must
set the extension as an additional property using the UTTypeTagSpecification and
public.filename-extension keys, as shown in Figure 4-2.
For detailed information about setting and exporting document UTIs, see Document-Based Application Preflight
in Document-Based App Programming Guide for iOS . For additional information about file wrappers, see Using
FileWrappers as File Containers (page 83).
Your app is notified of conflict versions through its file presenter objects. It is the job of the file presenter to
decide how best to resolve any conflicts that arise. Apps are encouraged to resolve conflicts quietly whenever
possible, either by merging the file contents or by discarding the older version if the older data is no longer
relevant. However, if discarding or merging the file contents is impractical or might result in data loss, your
app might need to prompt the user for help in choosing an appropriate course of action. For example, you
might let the user choose which version of the file to keep, or you might offer to save the older version under
a new name.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
54
iCloud File Management
Using iCloud Storage Responsibly
Apps should always attempt to resolve conflict versions as soon as possible. When conflict versions exist, all
of the versions remain in a user’s iCloud storage (and locally on any computers and iOS devices) until your app
resolves them. The current version of the file and any conflict versions are reported to your app using instances
of the NSFileVersion class.
To resolve conflicts:
1. Get the current file version using the currentVersionOfItemAtURL: class method of NSFileVersion.
2. Get an array of conflict versions using the unresolvedConflictVersionsOfItemAtURL: class method
of NSFileVersion.
3. For each conflict version object, perform whatever actions are needed to resolve the conflict. Options
include:
● Merging the conflict versions with the current file automatically, if it is practical to do so.
● Ignoring the conflict versions, if doing so does not result in any data loss.
● Prompting the user to select which version (current or conflict) to keep. This should always be your
last option.
4. Update the current file as needed.
● If the current file version remains the winner, you do not need to update the current file.
● If a conflict version is chosen as the winner, use a coordinated write operation to overwrite the contents
of the current file with the contents of the conflict version.
● If the user chooses to save the conflict version under a different name, create the new file with the
contents of the conflict version.
5. Set the resolved property of the conflict version objects to YES.
Setting this property to YES causes the conflict version objects (and their corresponding files) to be removed
from the user’s iCloud storage.
For more information about file versions and how you use them, see NSFileVersion Class Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
55
iCloud File Management
Using iCloud Storage Responsibly
● Rather than storing all documents, let a user choose which documents to store in an iCloud account. If a
user creates a large number of documents, storing all of those documents in iCloud could overwhelm that
user’s available space. Providing a way for a user to designate which documents to store in iCloud gives
that user more flexibility in deciding how best to use the available space.
● Remember that deleting a document removes it from a user’s iCloud account and from all of that user’s
computers and devices. Make sure that users are aware of this fact and confirm any delete operations. For
your app to refresh the local copy of a document, use the evictUbiquitousItemAtURL:error: method
of NSFileManager.
● When storing documents in iCloud, place them in a Documents directory whenever possible. Documents
inside a Documents directory can be deleted individually by the user to free up space. However, everything
outside that directory is treated as data and must be deleted all at once.
● Never store caches or other files that are private to your app in a user’s iCloud storage. A user’s iCloud
account should be used only for storing user data and content that cannot be re-created by your app.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
56
Using the Open and Save Panels
When working with user documents and files in OS X, the user should decide where those files reside in the
file system. The standard Open and Save panels provide you with an interface to use whenever you interact
with the user’s files. You present the Open panel when you want the user to select one or more existing files
or directories. Present the Save panel when you have a new user document that you need to write to disk.
Important: An iOS app should never use an Open or Save panel to prompt the user for the location of a
file within the app’s sandbox. iOS apps should always save files to known locations inside their sandbox,
and apps should use a custom interface when presenting those documents to the user. iOS apps can,
however, use a UIDocumentPickerViewController to prompt the user to import, export, open, or
move files to or from some areas outside the app’s sandbox. For more information, see the Document Picker
Programming Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
57
Using the Open and Save Panels
The Open Panel: Getting Existing Files or Directories
Listing 5-1 shows a custom method that presents the standard Open panel to the user. This panel uses the
default configuration options, which support the selection of a single file from all available file types. The
beginWithCompletionHandler: method displays the panel in a detached window and returns immediately.
The panel runs modally relative to the app and calls the supplied completion handler on the app’s main thread
when an item is selected. Upon the successful selection of a document, you need to provide the code to open
the document and present its window.
- (IBAction)openExistingDocument:(id)sender {
if (result == NSFileHandlingPanelOKButton) {
}];
Important: In OS X v10.6 and earlier, you must retain an Open panel before displaying it and release it
when you are done with it. Because the openPanel method returns an autoreleased object, the panel is
normally released shortly after it appears on screen. Retaining the panel prevents it from being deallocated
and dismissed prematurely. You do not need to retain the panel if it is attached to a window, and you do
not need to retain the panel in OS X v10.7 and when using ARC.
In a document-based app, requests to display the Open panel are handled by the openDocument: method
of the app’s document controller object, which is part of the app’s default responder chain. Instead of
implementing your own Open panel code, you might consider calling the openDocument: method instead.
Doing so ensures that your custom code and the default app infrastructure always display the same Open
panel. Customizing the panel at a later time also becomes easier because you have to make changes in only
one place.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
58
Using the Open and Save Panels
The Open Panel: Getting Existing Files or Directories
For more information about implementing a document-based app, see Mac App Programming Guide .
The NSOpenPanel object returned by the openPanel method is configured with the following default options:
● File selection: enabled
● Directory selection: disabled
● Resolve aliases: enabled
● Multiple selection: disabled
● Show hidden files: disabled
● File packages treated as directories: disabled
● Can create directories: disabled
Listing 5-2 shows a method you might implement in one of your NSDocument subclasses to import some files
and associate them with the document. After configuring the panel, this method uses the
beginSheetModalForWindow:completionHandler: method to present the panel as a sheet attached to
the document’s main window. If the user selects some files, the URLs method contains the corresponding file
and directory references to incorporate.
- (IBAction)importFilesAndDirectories:(id)sender {
[panel setCanChooseDirectories:YES];
[panel setAllowsMultipleSelection:YES];
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
59
Using the Open and Save Panels
The Save Panel: Getting a New Filename
if (result == NSFileHandlingPanelOKButton) {
}];
For single-window apps, associate the open panel with your app’s main window. For document-based apps,
associate it with the main window of the current document.
If you are not using the NSDocument infrastructure, you can create your own Save panels and display them
at appropriate times. The NSSavePanel class provides methods for creating and customizing the default Save
panel. When implementing your own document infrastructure, restrict your use of a Save panel to documents
the user creates and wants to save. Do not use a Save panel for files your app creates and manages implicitly.
For example, iPhoto does not prompt the user to specify the location of its main library file; it creates the file
in a well-known location without any user interactions. However, iPhoto does present a Save panel when the
user exports an image to disk.
Listing 5-3 shows a method that a document object might call when exporting a file to a new type. This method
assembles a new filename from the document’s existing name and the new type being saved. It then presents
the Save panel with the new name set as the default value and initiates the save operation as appropriate.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
60
Using the Open and Save Panels
The Save Panel: Getting a New Filename
- (void)exportDocument:(NSString*)name toType:(NSString*)typeUTI
// Build a new name for the file using the current name and
kUTTagClassFilenameExtension);
CFRelease(newExtension);
// Set the default name for the file and show the panel.
[panel setNameFieldStringValue:newName];
if (result == NSFileHandlingPanelOKButton)
}
}];
For more information about implementing a document-based app, see Mac App Programming Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
61
Using the Open and Save Panels
Using Filters to Limit the File Types That the User Can Select
Using Filters to Limit the File Types That the User Can Select
If your app is able to open only specific file types, you can use filtering to restrict the user’s selections to the
subset of files your app actually supports. The Open panel does not restrict the types of files the user can select
by default. To prevent the user from selecting files your app cannot handle, install one or more filters on the
Open panel. Files that do not match the provided filters are dimmed by the Open panel and cannot be selected
by the user. You can also install filters on the Save panel to dim unknown file types.
You specify filters as UTIs, filename extensions, or a combination of the two. After collecting your filter strings
into an array, you assign them to the panel using the setAllowedFileTypes: method. The panel handles
the actual filtration of files for you. You can change the filters while the panel is visible.
Listing 5-4 shows an example of how to configure the Open panel to allow the selection of image types only.
The NSImage class provides a convenience method for retrieving the supported image types. Because the
strings in the returned array are UTIs, the results are handed directly to the panel.
- (IBAction)askUserForImage:(id)sender {
[panel setAllowedFileTypes:imageTypes];
if (result == NSFileHandlingPanelOKButton) {
// Open the image.
}];
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
62
Using the Open and Save Panels
Adding an Accessory View to the Open and Save Panels
The basic process for adding an accessory view to an Open or Save panel is as follows:
1. Load the accessory view from a nib file. (You can create accessory views programmatically too, but using
a nib file is often easier.)
2. Create the panel.
3. Associate your view with the panel using the setAccessoryView: method.
4. Show the panel.
Compare the preceding steps to displaying a panel normally and the only difference is loading your view and
calling the setAccessoryView: method. All of the other work required to manage an accessory view and
respond to events is your responsibility.
A nib file is the simplest way to define an accessory view. Before setting up the nib file, you need to know
which object in your app is going to present the panel. For example, in a document-based app, your
NSDocument subclass is usually responsible for displaying any Open and Save panels. In general, the object
that presents the panel should also own the contents of the accessory view. With that in mind, the configuration
of your nib file would be as follows:
1. Create a new nib file whose contents are a single view.
2. Set the File’s Owner of the nib file to the object that presents the panel.
3. Configure the contents of the nib file’s top-level view object.
● Add any subviews, such as checkboxes, that you want to include in the accessory view.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
63
Using the Open and Save Panels
Adding an Accessory View to the Open and Save Panels
● You can change the class of the top-level view object if you want, but doing so is not required. If you
use a generic view as the main view, the underlying panel provides the appropriate background
appearance for the rest of your content.
4. Connect actions (as appropriate) to your views to facilitate interactions with your custom code. You should
implement the action methods themselves in the object you assigned as File’s Owner.
5. Connect outlets (as appropriate) for any controls you use to gather data passively from the user. The
completion handler for the panel can then use the outlets to access the data in the controls.
6. Size your accessory view to be as small as possible while still showing all subviews in their entirety.
7. Save the nib file.
When displaying an accessory view, the Open and Save panels show your entire accessory view. If your accessory
view is larger than the panel itself, the panel grows to accommodate your view. If the panel grows too large,
it could look strange or could cause problems on smaller screens. Most accessory views should have only a
few controls anyway. So if you find yourself adding more than ten controls, you might want to consider whether
an accessory view is appropriate or if there is a better way to gather the information.
For more information about configuring your views and the rest of your nib file, see Xcode Overview .
Loading the nib file for an accessory view is relatively simple as long as the nib file itself is configured properly.
The easiest way to configure the nib file is to assign the object that presents the panel as the File’s Owner of
the nib file itself. That way, any outlets and actions defined on the object are connected automatically and
ready to use as soon as the nib file is loaded into memory. Listing 5-5 shows an example of how this works.
The method in this example is implemented on an NSDocument object. When called, the method presents an
Open panel with an accessory view attached to the document’s main window. The accessory view itself contains
a single checkbox that is connected to a custom optionCheckbox outlet that the document object defines.
(The outlet itself is implemented using a property. ) The handler block uses the value of the checkbox to
determine how to open the file.
- (IBAction)openFileWithOptions:(id)sender {
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
64
Using the Open and Save Panels
Adding an Accessory View to the Open and Save Panels
// Load the nib file with the accessory view and attach it to the panel.
[panel setAccessoryView:self.accessoryView];
if (result == NSFileHandlingPanelOKButton) {
}];
If you create your accessory view programmatically, replace the if statement containing the call to the
loadNibNamed:owner: method with your custom view-creation code.
For more information on how to load objects from nib files, see Resource Programming Guide .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
65
Managing Files and Directories
Some of the most basic operations involving files and directories are creating them and moving them around
the file system. These operations are how your app builds the file system structure it needs to perform its tasks.
For most operations, the NSFileManager class should offer the functionality you need to create and manipulate
files. In the rare cases where it does not, you need to use BSD-level functions directly.
Creating Directories
When you want to create a custom directory, you do so using the methods of NSFileManager. A process can
create directories anywhere it has permission to do so, which always includes the current home directory and
may include other file system locations as well. You specify the directory to create by building a path to it and
passing your NSURL or NSString object to one of the following methods:
● createDirectoryAtURL:withIntermediateDirectories:attributes:error: (OS X v10.7 and
later only)
● createDirectoryAtPath:withIntermediateDirectories:attributes:error:
Listing 6-1 shows how to create a custom directory for app files inside the ~/Library/Application Support
directory. This method creates the directory if it does not exist and returns the path to the directory to the
calling code. Because this method touches the file system every time, you would not want to call this method
repeatedly to retrieve the URL. Instead, you might call it once and then cache the returned URL.
- (NSURL*)applicationDirectory
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
66
Managing Files and Directories
Creating New Files and Directories Programmatically
inDomains:NSUserDomainMask];
attributes:nil error:&theError])
return nil;
return dirPath;
If your code needs to run in OS X v10.6 and earlier, you can replace any calls to the
createDirectoryAtURL:withIntermediateDirectories:attributes:error: method with a similar
call to the createDirectoryAtPath:withIntermediateDirectories:attributes:error: method.
The only change you have to make is to pass a string-based path instead of a URL as the first parameter.
However, the NSURL class defines a path method that returns a string-based version of its path.
The NSFileManager methods are the preferred way to create new directories because of their simplicity.
However, you can also use the mkdir function to create directories yourself. If you do so, you are responsible
for creating intermediate directories and handling any errors that occur.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
67
Managing Files and Directories
Copying and Moving Files and Directories
Note: Any files you create inherit the permissions associated with the current user and process.
When writing the contents of a new file all at once, the system routines typically close the file after writing the
contents to disk. If the routine returns a file descriptor, you can use that descriptor to continue reading and
writing from the file. For information on how to read and write the contents of a file, see Techniques for Reading
and Writing Files Without File Coordinators (page 72).
The preceding methods move or copy a single file or directory at a time. When moving or copying a directory,
the directory and all of its contents are affected. The semantics for move and copy operations are the same as
in the Finder. Move operations on the same volume do not cause a new version of the item to be created.
Move operations between volumes behave the same as a copy operation. And when moving or copying items,
the current process must have permission to read the items and move or copy them to the new location.
Move and copy operations can potentially take a long time to complete, and the NSFileManager class
performs these operations synchronously. Therefore, it is recommended that you execute any such operations
on a concurrent dispatch queue and not on your app’s main thread. Listing 6-2 shows an example that does
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
68
Managing Files and Directories
Copying and Moving Files and Directories
just that by asynchronously creating a backup of a fictional app’s private data. (For the sake of the example,
the private data is located in the ~/Library/Application Support/bundleID /Data directory, where
bundleID is the actual bundle identifier of the app.) If the first attempt to copy the directory fails, this method
checks to see whether a previous backup exists and removes it if it does. It then proceeds to try again and
aborts if it fails a second time.
- (void)backupMyApplicationData {
inDomains:NSUserDomainMask];
URLByAppendingPathComponent:@"Data"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^{
// It's good habit to alloc/init the file manager for move/copy operations,
NSError* anError;
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
69
Managing Files and Directories
Deleting Files and Directories
});
}
}
For details on how to use the NSFileManager methods, see NSFileManager Class Reference .
When using these methods to delete files, realize that you are permanently removing the files from the file
system; these methods do not move the file to the Trash where it can be recovered later.
For details on how to use the NSFileManager methods, see NSFileManager Class Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
70
Managing Files and Directories
Creating and Handling Invisible Files
Even if you mark a file as invisible, there are still ways for the user to see it. Users can always view the true file
system contents using the Terminal app. Unlike the Finder, the command line in the Terminal window displays
the actual names of items in the file system and not their display names or localized names. You can also show
hidden files in the Open and Save panels (using the setShowsHiddenFiles: method) in cases where you
want the user to be able to select them for viewing or editing.
Regardless of whether a file contains a leading period, your app’s code can always see hidden files. Methods
that enumerate the contents of directories generally include hidden files in the enumeration. The only exceptions
to this rule is the meta directories . and .. that represent the current and parent directories. Therefore, any
code that enumerates the contents of a directory should be prepared to handle hidden files and deal with
them appropriately, usually by just ignoring them.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
71
Techniques for Reading and Writing Files Without
File Coordinators
Reading and writing files involves transferring a sequence of bytes between your code and the underlying
disk. This is the lowest-level form of file management but is also the foundation for more sophisticated
techniques as well. At some point, even the most sophisticated data structures have to be turned into a
sequence of bytes before they can be stored on disk. Similarly, that same data must be read from the disk as
a sequence of bytes before it can be used to reconstruct the more sophisticated data structures that it represents.
There are several different technologies for reading and writing the contents of files, nearly all of which are
supported by both iOS and OS X. All of them do essentially the same thing but in slightly different ways. Some
technologies require you to read and write file data sequentially, while others may allow you to jump around
and operate on only part of a file. Some technologies provide automatic support for reading and writing
asynchronously, while others execute synchronously so that you have more control over their execution.
Choosing from the available technologies is a matter of deciding how much control you want over the reading
and writing process and how much effort you want to spend writing your file management code. Higher-level
technologies like Cocoa streams limit your flexibility but provide an easy-to-use interface. Lower-level
technologies like POSIX and Grand Central Dispatch (GCD) give you maximum flexibility and power but require
you to write a little more code.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
72
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Asynchronously
Stream objects use the run loop of the current thread to schedule read and write operations on the stream.
An input stream wakes up the run loop and notifies its delegate when there is data waiting to be read. An
output stream wakes up the run loop and notifies its delegate when there is space available for writing data.
When operating on files, this behavior usually means that the run loop is woken up several times in quick
succession so that your delegate code can read or write the file data. It also means that your delegate code is
called repeatedly until you close the stream object, or in the case of input streams until the stream reaches
the end of the file.
For information and examples about how to set up and use stream objects to read and write data, see Stream
Programming Guide .
Dispatch I/O channels are the preferred way to read and write files because they give you direct control over
when file operations occur but still allow you to process the data asynchronously on a dispatch queue. A
dispatch I/O channel is an dispatch_io_t structure that identifies the file whose contents you want to read
or write. Channels can be configured for stream-based access or random access of files. A stream-based channel
forces you to read or write file data sequentially, whereas a random-access channel lets you read or write at
any offset from the beginning of the file.
If you do not want the trouble of creating and managing a dispatch I/O channel, you can use the
dispatch_read or dispatch_write functions to perform a single read or write operation on a file descriptor.
These methods are convenient for situations where you do not want or need the overhead of creating and
managing a dispatch I/O channel. However, you should use them only when performing a single read or write
operation on a file. If you need to perform multiple operations on the same file, creating a dispatch I/O channel
is much more efficient.
Dispatch sources allow you to process files in a way that is similar to Cocoa stream objects. Like stream objects,
they are used more often with sockets or data sources that send and receive data sporadically but they can
still be used with files. A dispatch source schedules its associated event handler block whenever there is data
waiting to be read or space available for writing. For files, this usually results in the block being scheduled
repeatedly and in quick succession until you explicitly cancel the dispatch source or it reaches the end of the
file it is reading.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
73
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Asynchronously
For more information about creating and using dispatch sources, see Concurrency Programming Guide . For
information about the dispatch_read or dispatch_write functions, or any other GCD functions, see Grand
Central Dispatch (GCD) Reference .
Listing 7-1 shows a simple example of how to open a dispatch I/O channel using an NSURL object. In this case,
the channel is configured for random read-access and assigned to a custom property of the current class. The
queue and block act to clean up the channel in the event that an error occurs during creation or at the end of
the channel’s lifecycle. If an error occurs during creation, you can use the error code to determine what
happened. An error code of 0 indicates that the channel relinquished control of its file descriptor normally,
usually as a result of calling the dispatch_io_close function, and that you can now dispose of the channel
safely.
-(void)openChannelWithURL:(NSURL*)anURL {
self.channel = dispatch_io_create_with_path(DISPATCH_IO_RANDOM,
0, // No extra flags
dispatch_get_main_queue(),
^(int error){
if (error == 0) {
dispatch_release(self.channel);
self.channel = NULL;
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
74
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Asynchronously
});
After creating a dispatch channel, you can store a reference to the resulting dispatch_io_t structure and
use it to initiate read or write calls at your convenience. If you created a channel that supports random access,
you can start reading or writing at any location. If you create a stream-based channel, any offset value you
specify as a starting point is ignored and data is read or written at the current location. For example, to read
the second 1024 bytes from a channel that supports random access, your read call might look similar to the
following:
dispatch_io_read(self.channel,
if (error == 0) {
});
A write operation requires you to specify the bytes you want written to the file, the location at which to begin
writing (for random access channels), and a handler block with which to receive progress reports. You initiate
write operations using the dispatch_io_write function, which is described in Grand Central Dispatch (GCD)
Reference .
To write data to a dispatch I/O channel, your code must provide a dispatch_data_t structure with the bytes
to write. You do this using the dispatch_data_create function, which takes a pointer to a buffer and the
size of the buffer and returns a dispatch_data_t structure that encapsulates the data from that buffer. How
the data object encapsulates the buffer depends on the destructor you provide when calling the
dispatch_data_create function. If you use the default destructor, the data object makes a copy of the
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
75
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Asynchronously
buffer and takes care of releasing that buffer at the appropriate time. However, if you do not want the data
object to copy the buffer you provide, you must provide a custom destructor block to handle any needed
cleanup when the data object itself is released.
Note: If you have multiple data buffers that you want to write to a file as a single contiguous block
of data, you can create a single dispatch data object that represents all of those buffers. Using the
dispatch_data_create_concat function, you can append additional data buffers to a
dispatch_data_t structure. The buffers themselves can all be independent and in different parts
of memory but the dispatch data object collects them and represents them as a single entity. (You
can even use the dispatch_data_create_map function to generate a contiguous version of your
buffers.) Especially for disk-based operations, concatenating multiple buffers lets you write large
amounts of data to a file using one call to the dispatch_io_write function, which is much more
efficient than calling dispatch_io_write separately for each independent buffer.
To extract bytes from a dispatch data object, you use the dispatch_data_apply function. Because dispatch
data objects are opaque, you use this function to iterate over the buffers in the object and process them using
a block that you provide. For a dispatch data object with a single contiguous buffer, your block is called once.
For a data object with multiple buffers, your block is called as many times as there are buffers. Each time your
block is called, it is passed a data buffer and some information about that buffer.
Listing 7-2 shows an example that opens a channel and reads a UTF8 formatted text file, creating NSString
objects for the contents of the file. This particular example reads 1024 bytes at a time, which is an arbitrary
amount and may not yield the best performance. However, it does demonstrate the basic premise of how to
use the dispatch_io_read function in combination with the dispatch_data_apply function to read the
bytes and then convert them into a form that your app might want. In this case, the block that processes the
bytes uses the dispatch data object’s buffer to initialize a new string object. It then hands the string off to the
custom addString:toFile: method, which in this case would store it for later use.
Listing 7-2 Reading the bytes from a text file using a dispatch I/O channel
- (void)readContentsOfFile:(NSURL*)anURL {
self.channel = dispatch_io_create_with_path(DISPATCH_IO_RANDOM,
0, // No extra flags
dispatch_get_main_queue(),
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
76
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Asynchronously
^(int error){
// Cleanup code
if (error == 0) {
dispatch_release(self.channel);
self.channel = nil;
});
if (!self.channel)
return;
NSNumber* theSize;
NSInteger fileSize = 0;
off_t currentOffset = 0;
if (error)
return;
dispatch_data_apply(data,
(dispatch_data_applier_t)^(dispatch_data_t region,
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
77
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Synchronously
length:size encoding:NSUTF8StringEncoding]
autorelease];
[pool release];
});
});
}
For more information about the functions you use to manipulate dispatch data objects, see Grand Central
Dispatch (GCD) Reference .
For custom document types that use a binary or private file format, you can use the NSData or NSMutableData
class to transfer your custom data to and from disk. You can create new data objects in many different ways.
For example, you can use a keyed archiver object to convert a graph of objects into a linear stream of bytes
enclosed in a data object. If you have a binary file format that is very structured, you can append bytes to an
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
78
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Synchronously
NSMutableData object and build your data object piece by piece. When you are ready to write the data object
to disk, use the writeToURL:atomically: or writeToURL:options:error: method. These methods
allow you to create the corresponding on-disk file in one step.
Note: In iOS, one of the options you can pass to the writeToURL:options:error: method allows
you to specify whether you want the contents of the file encrypted. If you specify one of these
options, the contents are encrypted immediately to ensure the security of the file.
To read data back from disk, use the initWithContentsOfURL:options:error: method to obtain a data
object based on the contents of your file. You can use this data object to reverse the process you used when
creating it. Thus, if you used a keyed archiver to create the data object, you can use a keyed unarchiver to
re-create your object graph. If you wrote the data out piece by piece, you can parse the byte stream in the
data object and use it to reconstruct your document’s data structures.
Apps that use the NSDocument infrastructure typically interact with the file system indirectly using NSData
objects. When the user saves a document, the infrastructure prompts the corresponding NSDocument object
for a data object to write to disk. Similarly, when the user opens an existing document, it creates the document
object and passes it a data object with which to initialize itself.
For more information about the NSData and NSMutableData classes, see Foundation Framework Reference .
For more information about using the document infrastructure in an OS X app, see Mac App Programming
Guide .
Listing 7-3 shows a very simple method that reads the entire contents of a file using a file handle object. The
fileHandleForReadingFromURL:error: method creates the file handle object as an autoreleased object,
which causes it to be released automatically at some point after this method returns.
- (NSData*)readDataFromFileAtURL:(NSURL*)anURL {
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
79
Techniques for Reading and Writing Files Without File Coordinators
Reading and Writing Files Synchronously
if (aHandle)
return fileContents;
For more information about the methods of the NSFileHandle class, see NSFileHandle Class Reference .
Important: On some file systems, there is no guarantee that a successful write call results in the actual
writing of bytes to the file system. For some network file systems, written data might be sent to the server
at some point after your write call. To verify that the data actually made it to the file, use the fsync function
to force the data to the server or close the file and make sure it closed successfully—that is, the close
function did not return -1.
Listing 7-4 shows a simple function that uses POSIX calls to read the first 1024 bytes of a file and return them
in an NSData object. If the file has fewer than 1024 bytes, the method reads as many bytes as possible and
truncates the data object to the actual number of bytes.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
80
Techniques for Reading and Writing Files Without File Coordinators
Getting and Setting File Metadata Information
- (NSData*)readDataFromFileAtURL:(NSURL*)anURL {
if (fd == -1)
return nil;
if (theData) {
[theData setLength:actualBytes];
close(fd);
return theData;
Because there is a limit to the number of open file descriptors an app may have at any given time, you should
always close file descriptors as soon as you are done using them. File descriptors are used not only for open
files but for communications channels such as sockets and pipes. And your code is not the only entity creating
file descriptors for your app. Every time you load a resource file or use a framework that communicates over
the network, the system creates a file descriptor on behalf of your code. If your code opens large numbers of
sockets or files and never closes them, system frameworks may not be able to create file descriptors at critical
times.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
81
Techniques for Reading and Writing Files Without File Coordinators
Getting and Setting File Metadata Information
● Get and set most content metadata information (including Apple-specific attributes) using the NSURL
class.
● Get and set basic file-related information using the NSFileManager class.
The NSURL class offers a wide range of file-related information, including information that is standard for the
file system (such as file size, type, owner, and permissions) but also a lot of Apple-specific information (such
as the assigned label, localized name, the icon associated with the file, whether the file is a package, and so
on). In addition, some methods that take URLs as arguments allow you to cache attributes while you are
performing other operations on the file or directory. Especially when accessing large numbers of files, this type
of caching behavior can improve performance by minimizing the number of disk-related operations. Regardless
of whether attributes are cached, you retrieve them from the NSURL object using its
getResourceValue:forKey:error: method and set new values for some attributes using the
setResourceValue:forKey:error: or setResourceValues:error: method.
Even if you are not using the NSURL class, you can still get and set some file-related information using the
attributesOfItemAtPath:error: and setAttributes:ofItemAtPath:error: methods of the
NSFileManager class. These methods let you retrieve information about file system items like their type, size,
and the level of access currently supported. You can also use the NSFileManager class to retrieve more
general information about the file system itself, such as its size, the amount of free space, the number of nodes
in the file system, and so on. Note that you are only able to get a subset of resources for iCloud files.
For more information about the NSURL and NSFileManager classes, and the attributes you can obtain for
files and directories, see NSURL Class Reference and NSFileManager Class Reference .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
82
Using FileWrappers as File Containers
An NSFileWrapper instance holds a file’s contents in dynamic memory. In this role it enables a document
object to embed a file, treating it as a unit of data that can be displayed as an image (and possibly edited in
place), saved to disk, or transmitted to another app. It can also store an icon for representing the file in a
document or in a dragging operation.
Instances of this class are referred to as file wrapper objects , or simply as file wrappers . A file wrapper can be
one of three specific types: a regular file wrapper, which holds the contents of a single actual file; a directory
wrapper, which holds a directory and all of the files or directories within it; or a link wrapper, which simply
represents a symbolic link in the file system.
Because the purpose of a file wrapper is to represent files in memory, it’s very loosely coupled to any disk
representation. A file wrapper doesn’t record the path to the disk representation of its contents. This allows
you to save the same file wrapper with different URLs, but it also requires you to record those URLs if you want
to update the file wrapper from disk later.
Note: When an NSFileWrapper instance is specified as the item for file coordination, all the files
within the file wrapper are automatically part of that file coordination. It is not necessary to mange
each file or directory individually.
Three convenience methods each create a file wrapper of a specific type: initRegularFileWithContents:,
initDirectoryWithFileWrappers:, and initSymbolicLinkWithDestination:. Because each
initialization method creates file wrappers of different types or states, they’re all designated initializers for this
class—subclasses must meaningfully override them all as necessary.
Some file wrapper methods apply only to a specific wrapper type, and an exception is raised if a method sent
to a file wrapper of the wrong type. To determine the type of a file wrapper, use the isRegularFile,
isDirectory, and isSymbolicLink methods.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
83
Using FileWrappers as File Containers
Working with Directory Wrappers
A file wrapper stores file system information (such as modification time and access permissions), which it
updates when reading from disk and uses when writing files to disk. The fileAttributes method returns
this information in the format described in the NSFileManager method attributesOfItemAtPath:error:.
You can also set the file attributes using the setFileAttributes: method.
The NSFileWrapper class allows you to set a preferred filename for save operations, and it records the last
filename it was actually saved to; the preferredFilename and filename methods return these names. This
feature is most important for directory wrappers, though, and so is discussed under Working with Directory
Wrappers.
When saving a file wrapper to disk, you typically determine the directory you want to save it in, then append
the preferred filename to that directory URL, and use the
writeToURL:options:originalContentsURL:error: method, which saves the file wrapper’s contents
and updates the file attributes. You can save a file wrapper under a different name if you like, but this doing
so may result in the recorded filename differing from the preferred filename, depending on how you invoke
the writeToURL:options:originalContentsURL:error: method.
Besides saving its contents to disk, a file wrapper can reread them from disk when necessary. The
matchesContentsOfURL: method determines whether a disk representation may have changed, based on
the file attributes stored the last time the file was read or written. If the file wrapper’s modification time or
access permissions are different from those of the file on disk, this method returns YES. You can then use
readFromURL:options:error: to re-read the file from disk.
Finally, to transmit a file wrapper to another process or system (for example, using the pasteboard), you use
the serializedRepresentation method to get an NSData object containing the file wrapper’s contents
in the NSFileContentsPboardType format. You can safely transmit this representation over whatever
channel you choose. The recipient of the representation can then reconstitute the file wrapper using the
initWithSerializedRepresentation: method.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
84
Using FileWrappers as File Containers
Working with Directory Wrappers
A directory wrapper stores its contents in an NSDictionary object, which you can retrieve using the
fileWrappers method. The keys of this dictionary are based on the preferred filenames of each file wrapper
contained in the directory wrapper. There exist, then, three identifiers for a file wrapper within a directory
wrapper:
● Preferred filename. This identifier doesn’t uniquely identify the file wrapper, but the other identifiers are
always based on it.
● Dictionary key. This identifier is always equal to the preferred name when there are no other file wrappers
of the same preferred name in the same directory wrapper. Otherwise, it’s a string made by adding a
unique prefix to the preferred filename. Note that the same file wrapper can have a different dictionary
key for each directory wrapper that contains it. You use the dictionary key to retrieve the file wrapper
object in memory, in order to get its contents or its filename (that is, to update it from disk). You can get
a file wrapper’s dictionary key by sending a keyForFileWrapper: message to the directory wrapper
that contains it.
● Filename. This identifier is usually based on the preferred filename, but isn’t necessarily the same as it or
the dictionary key. You use the filename to update a single file wrapper relative to the path of the directory
wrapper that contains it. Note that the filename may change whenever you save a directory wrapper
containing the file wrapper. Particularly if the file wrapper has been added to several different directory
wrappers. Thus, you should always retrieve the filename from the file wrapper itself each time you need
it rather than caching it.
When working with the contents of a directory wrapper, you can use a dictionary enumerator to retrieve each
file wrapper and perform whatever operation you need. With the exceptions of saving and updating, a directory
file wrapper defines no recursive operations for its contents. To set the file attributes for all contained file
wrappers, or to perform any other such operation, you must define a recursive method that examines the type
of each file wrapper and invokes itself again for any directory wrapper it encounters.
If you are saving directory file wrappers to an iCloud container, you must export a properly formatted UTI for
your document. For more information, see Working With File Wrappers (page 53).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
85
Performance Tips
If your app works with a lot of files, the performance of its file-related code is very important. Relative to other
types of operations, accessing files on disk is one of the slowest operations a computer can perform. Depending
on the size and number of files, it can take anywhere from a few milliseconds to several minutes to read files
from a disk-based hard drive. Therefore, you should make sure your code performs as efficiently as possible
under even light to moderate work loads.
If your app slows down or becomes less responsive when it starts working with files, use the Instruments app
to gather some baseline metrics. Instruments can show you how much time your app spends operating on
files and help you monitor various file-related activity. As you fix each problem, be sure to run your code in
Instruments again and record the results so that you can verify whether your changes worked.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
86
Performance Tips
Use Modern File-System Interfaces
You should also prefer routines that accept block objects over those that accept callback functions or methods.
Blocks are a convenient and more efficient way to implement callback-type behaviors. In practice, blocks often
require much less code to implement because they do not require you to define and manage a context data
structure for passing data. Some routines might also execute your block by scheduling it in a GCD queue, which
can also improve performance.
General Tips
What follows are some basic recommendations for reducing the I/O activity of your program. These may help
improve your file-system-related performance, but as with all tips, be sure to measure before and after so that
you can verify any performance gains.
● Minimize the number of file operations you perform. Moving data from a local file system into memory
takes a significant amount of time. File-system access times are generally measured in milliseconds, which
corresponds to several millions of clock cycles spent waiting for data to be fetched from disk. And if the
target file system is located on a server halfway around the world, network latency increases the delay in
retrieving the data.
● Reuse path objects. If you take the time to create an NSURL for a file, reuse that object as much as you
can rather than create it each time you need it. Locating files and building URLs or pathname information
takes time and can be expensive. Reusing the objects created from those operations saves time and
minimizes your app’s interactions with the file system.
● Choose an appropriate read buffer size. When reading data from the disk to a local buffer, the buffer
size you choose can have a dramatic effect on the speed of the operation. If you are working with relatively
large files, it does not make sense to allocate a 1K buffer to read and process the data in small chunks.
Instead, create a larger buffer (say 128K to 256K in size) and read much or all of the data into memory
before processing it. The same rules apply for writing data to the disk: Write data as sequentially as you
can using a single file-system call.
● Read data sequentially instead of jumping around in a file. The kernel transparently clusters I/O
operations, which makes sequential reads much faster.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
87
Performance Tips
General Tips
● Avoid skipping ahead in an empty file before writing data. The system might have to write zeroes into
the intervening space to fill the gap. You should always have a good reason for including “holes” in your
files at write time and should know that doing so might incur a performance penalty. For more information,
see Zero-Fill Delays Provide Security at a Cost (page 89).
● Defer I/O operations until your app needs the data. The golden rule of being lazy applies to disk
performance as well as many other types of performance.
● Do not abuse the preferences system. Use the preferences system to capture only user preferences (such
as window positions, view settings, and user provided preferences) and not data that can be inexpensively
recomputed. Recomputing simple values is significantly faster than reading the same value from disk.
● Do not assume that caching files in memory will speed up your app. Caching files in memory increases
memory usage, which can decrease performance in other ways. Plus, the system may cache some file data
for you automatically, so creating your own caches might make things even worse; see The System Has
its Own File Caching Mechanism (page 88).
Caching is most appropriate for files you plan to access multiple times. If you have files that you intend to use
only once, either disable the caches or map the file into memory.
Apps can call the BSD fcntl function with the F_NOCACHE flag to enable or disable caching for a file. For
more information about this function, see fcntl.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
88
Performance Tips
General Tips
Note: When reading uncached data, it is recommended that you use 4K-aligned buffers. This gives
the system more flexibility in how it loads the data into memory and can result in faster load times.
Important: If you map a file into memory and the file becomes inaccessible—because the disk containing
the file was ejected or the network server containing the file is unmounted—your app will crash with a
SIGBUS error.
For more information about mapping files into memory, see File System Advanced Programming Topics .
For both reading and writing operations, the system delays the writing of zeroes until the last possible moment.
When you close a file after writing to it, the system writes zeroes to any portions of the file your code did not
touch. When reading from a file, the system writes zeroes to new areas only when your code attempts to read
from that area or when it closes the file. This delayed-write behavior avoids redundant I/O operations to the
same area of a file.
If you notice a delay when closing your files, it is likely because of this zero-fill behavior. Make sure you do the
following when working with files:
● Write data to files sequentially. Gaps in writing must be filled with zeros when the file is saved.
● Do not move the file pointer past the end of the file and then close the file.
● Truncate files to match the length of the data you wrote. For scratch files you plan to delete, truncate the
file to zero-length.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
89
OS X Library Directory Details
The Library directories are where the system and your code store all of their related data and resources. In
OS X, this directory can contain many different subdirectories, most of which are created automatically by the
system. In iOS, the app installer creates only a few subdirectories in ~/Library (such as Caches and
Preferences) and your app is responsible for creating all others.
Table A-1 lists some of the common subdirectories you might find in a Library directory in OS X along with
the types of files that belong there. You should always use these directories for their intended purposes. For
information about the directories your app should be using the most, see The Library Directory Stores
App-Specific Files (page 21).
Application Contains all app-specific data and support files. These are the files that your
Support app creates and manages on behalf of the user and can include files that
contain user data.
By convention, all of these items should be put in a subdirectory whose name
matches the bundle identifier of the app. For example, if your app is named
MyApp and has the bundle identifier com.example.MyApp, you would put
your app’s user-specific data files and resources in the
~/Library/Application Support/com.example.MyApp/ directory.
Your app is responsible for creating this directory as needed.
Resources required by the app to run must be placed inside the app bundle
itself.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
90
OS X Library Directory Details
Caches Contains cached data that can be regenerated as needed. Apps should never
rely on the existence of cache files. Cache files should be placed in a directory
whose name matches the bundle identifier of the app.
By convention, apps should store cache files in a subdirectory whose name
matches the bundle identifier of the app. For example, if your app is named
MyApp and has the bundle identifier com.example.MyApp, you would put
user-specific cache files in the ~/Library/Caches/com.example.MyApp/
directory.
ColorPickers Contains resources for picking colors according to a certain model, such as
the HLS (Hue Angle, Saturation, Lightness) picker or RGB picker.
Containers Contains the home directories for any sandboxed apps. (Available in the user
domain only.)
Documentation Contains documentation files and Apple Help packages intended for the users
and administrators of the computer. (Apple Help packages are located in the
Documentation/Help directory.) In the local domain, this directory contains
the help packages shipped by Apple (excluding developer documentation).
Frameworks Contains frameworks and shared libraries. The Frameworks directory in the
system domain is for Apple-provided frameworks only. Developers should
install their custom frameworks in either the local or user domain.
Internet Plug-ins Contains plug-ins, libraries, and filters for web-browser content.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
91
OS X Library Directory Details
LaunchAgents Specifies the agent apps to launch and run for the current user.
LaunchDaemons Specifies the daemons to launch and run as root on the system.
Logs Contains log files for the console and specific system services. Users can also
view these logs using the Console app.
Mail Contains the user’s mailboxes. (Available in the user domain only.)
PreferencePanes Contains plug-ins for the System Preferences app. Developers should install
their custom preference panes in the local domain.
Preferences Contains the user’s preferences. You should never create files in this directory
yourself. To get or set preference values, you should always use the
NSUserDefaults class or an equivalent system-provided interface.
Printers In the system and local domains, this directory contains print drivers, PPD
plug-ins, and libraries needed to configure printers. In the user domain, this
directory contains the user’s available printer configurations.
QuickLook Contains QuickLook plug-ins. If your app defines a QuickLook plug-in for
viewing custom document types, install it in this directory (user or local
domains only).
Screen Savers Contains screen saver definitions. See Screen Saver Framework Reference for
a description of the interfaces used to create screen saver plug-ins.
Scripting Contains scripts and scripting resources that extend the capabilities of
Additions AppleScript.
StartupItems (Deprecated) Contains system and third-party scripts and programs to be run
at boot time. (See Daemons and Services Programming Guide for more
information about starting up processes at boot time.)
Web Server Contains web server content. This directory contains the CGI scripts and
webpages to be served. (Available in the local domain only.)
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
92
File System Details
This appendix includes information about the file systems supported by OS X and iOS.
HFS Mac OS Standard file system. Standard Macintosh file system for older versions of Mac
OS. File systems of this type are treated as read only as of OS X v10.6.
HFS Plus Mac OS Extended file system. Standard Macintosh file system for OS X.
WebDAV Used for directly accessing files on the web. For example, iDisk uses WebDAV for
accessing files.
UDF Universal Disk Format. The standard file system for all forms of DVD media (video, ROM,
RAM and RW) and some writable CD formats.
FAT The MS-DOS file system, with 16- and 32-bit variants. Fat 12-bit is not supported.
SMB/CIFS Used for sharing files with Microsoft Windows SMB file servers and clients.
AFP Apple Filing Protocol. The primary network file system for all versions of Mac OS.
NFS Network File System. A commonly-used UNIX file sharing standard. OS X supports NFSv2
and NFSv3 over TCP and UDP. OS X 10.7 also supports NFSv4 over TCP.
FTP A file system wrapper for the standard Internet File Transfer Protocol.
Xsan Apple’s 64-bit cluster file system used in storage area networks.
NTFS A standard file system for computers running the Windows operating system.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
93
File System Details
The Finder
CDDAFS A file system used to mount audio CDs and present audio tracks on disc to users as
AIFF-C encoded files.
Many file systems require specific separator characters to denote paths. It is best to use the NSURL file
construction methods to construct strings rather than doing so manually.
The Finder
Because the Finder is the user’s main access to the file system in OS X, it helps to understand a little about how
the Finder presents and works with files.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
94
File System Details
File Types and Creator Codes
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
95
File System Details
OS X File System Security
Security Schemes
OS X provides three file system security schemes: UNIX (BSD) permissions, POSIX access control lists (ACLs),
and sandbox entitlements. In addition, the BSD layer provides several per-file flags that override UNIX
permissions. These schemes are described in the sections that follow.
In addition, OS X allows admin users to disable ownership and permissions checking for removable volumes
on a per-volume basis by choosing Get Info on the volume in Finder, then checking the “Ignore ownership on
this volume” checkbox.
Sandbox Entitlements
OS X supports the use of a sandbox to limit an app’s ability to access files. These limits override any permissions
the app might otherwise have. Sandbox limits are subtractive, not additive. Therefore, the file system permissions
represent the maximum access an app might be allowed if its sandbox also permits that access.
POSIX ACLs
Starting with OS X v10.4, the Mach and BSD permissions policies are supplemented by support in the kernel
for ACLs (access control lists), which are data structures that provide much more detailed control over
permissions than does BSD. For example, ACLs allow the system administrator to specify that a specific user
can delete a file but cannot write to it. ACLs also provide compatibility with Active Directory and with the
SMB/CIFS networks used by the Windows operating system. For more information on ACL support in OS X for
different network file systems, see Network File Systems (page 110).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
96
File System Details
OS X File System Security
An ACL consists of an ordered list of ACEs (access control entries), each of which associates a user or group
with a set of permissions and specifies whether each permission is allowed or denied. ACEs also include
attributes related to inheritance (see Inheritance of Permissions (page 100)).
Note: File system ACLs are not related to the ACLs used by keychains, as described in Keychain
Services Programming Guide .
write Open file for write Add a file entry to the directory
execute Execute file Search through the directory (to access files
or directories within it)
read permissions Read file permissions (ACL) Read directory permissions (ACL)
write permissions Write file permissions (ACL) Write directory permissions (ACL)
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
97
File System Details
OS X File System Security
Unlike BSD, which specifies three permissions for each file (one for the file’s owner, one for members of the
file’s group, and one for everyone else), an ACL can specify different permissions for each ACE. Another contrast
between ACLs and BSD is that, whereas in BSD the file owner must be an individual, in the ACL permission
scheme the file owner can be either a user or a group. If a file is owned by a group, its GID (used by BSD) and
group UUID are always coherent (that is, there is always a simple, 1:1 mapping between them). However,
because BSD does not support the concept of a group as owner of a file, in this case the system assigns a
special UID that identifies the file as owned by “not a user” and the owner UUID represents a group. If the file
is owned by a single individual, its UID and owner UUID are coherent.
The owner of a file using an ACL has certain irrevocable permissions (read and write permissions) regardless
of the contents of the ACL. If the file is owned by an individual, the group UUID associates a group with a file
system object and affects the inheritance of certain ACEs (see Inheritance of Permissions (page 100)) but does
not confer any special permissions on the group.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
98
File System Details
OS X File System Security
authorization includes a credential (which identifies the requesting entity) and the permissions required for
the operation. OS X v10.4 and later evaluates permissions using the following algorithm (also, see Inheritance
of Permissions (page 100) for a discussion of inherited permissions):
1. If the requested permissions would change the object, and the file system is read-only or the object is
marked as immutable, the operation is denied.
2. If the entity making the request is the root user, the operation is allowed.
3. If the entity making the request is the object’s owner, the requestor is given Read Permissions and Write
Permissions access. If that is sufficient to satisfy the request, the operation is allowed.
4. If the object has an ACL, the ACEs in the ACL are scanned in order. (Those with deny associations are
usually placed before those with allow associations.) Each ACE is evaluated according to the following
criteria until either a required permission has been denied, all required permissions have been allowed,
or the end of the ACL is reached:
a. The ACE is checked for applicability. The ACE is not considered applicable if it does not refer to any
of the requested permissions. In addition, the requesting entity must be the same as the entity named
in the ACE, or the requestor must be a member of a group named in the ACE. (Groups may be nested
and an external directory service may be used to resolve group membership.) Non-applicable ACEs
are ignored.
b. If the ACE denies any of the requested permissions, then the request is denied. (Note that Read
Permissions and Write Permissions are granted to the object’s owner, regardless of whether allowed
or denied by ACEs.)
c. If the ACE allows any of the requested permissions, the system adds this permission to the list of
granted permissions. If the granted permissions include all the requested permissions, the request is
allowed and the process stops. If the list is not complete, the system goes on to check the next ACE.
5. If the end of the ACL is reached without finding all of the required permissions, and if the object also has
BSD permissions, then the system checks the unsatisfied permissions against the BSD permissions. If these
are sufficient to grant all required permissions, the request is allowed. If the permission requested has no
BSD equivalent (such as “take ownership”), then it is considered still outstanding and the request is denied.
6. If the file system object has no ACL, then permissions are evaluated according to the BSD security policies,
as described in UNIX Permissions (page 105) and BSD File Flags (page 103).
The credential of the requesting entity is equivalent to the effective UID (that is, the EUID) of the program
attempting to open or execute a file. The EUID is normally the same as the UID of the user or process that
executes the process., but it can differ in special circumstances (involving the setuid bit) as described in Owner
or Root Security Policy.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
99
File System Details
OS X File System Security
Inheritance of Permissions
BSD permissions are assigned only on a per-file basis, so that the permissions assigned to a directory do not
affect the permissions of a new file or subdirectory created in that directory. Although you can apply the
permissions of a directory to enclosed items, doing so is a one-time operation. Any newly created files or
subdirectories are not affected—they are created with default permissions.
With ACLs, by contrast, newly created files and subdirectories can inherit permissions from their enclosing
directory. Each ACE on a directory can contain any combination of the following inheritance flags:
● Inherited (this ACE was inherited)
● File Inherit (this ACE should be inherited by files created within this directory)
● Directory Inherit (this ACE should be inherited by directories created within this directory)
● Inherit Only (this ACE should not be checked during authorization)
● No Propagate Inherit (this ACE should be inherited only by direct children; that is, the ACE should lose any
Directory Inherit or File Inherit bit when inherited)
When it creates a new file, the kernel goes through the entire access control list of the parent directory and
copies to the file’s ACL any ACEs that are marked for file inheritance. Similarly, when it creates a new subdirectory,
the kernel copies to the subdirectory’s ACL any ACEs that are marked for directory inheritance.
If a file is copied and pasted into a directory, the kernel replicates the contents of the source file into a new
file at the destination. Because it is creating a new file, the system checks the ACL of the parent directory and
adds any inherited ACEs to whatever ACEs were in the original file. If a file is moved into a directory, on the
other hand, the original file is not replicated and no ACEs are inherited. In this case, the parent directory’s ACEs
are added to the moved file only if the administrator specifically propagates ACEs from the parent directory
through contained files and subdirectories. Similarly, once a file has been created, changing the ACL of the
parent directory does not affect the ACL of contained files and subdirectories unless the administrator specifically
propagates the change.
In BSD, applying a directory’s permissions to enclosed files and subdirectories completely replaces the
permissions of the enclosed objects. With ACLs, in contrast, inherited ACEs are added to other ACEs already
on the file or directory.
The order in which ACEs are placed in an ACL—and therefore the order in which they are evaluated to determine
permissions—is as follows:
1. Explicitly specified deny associations
2. Explicitly specified allow associations
3. Inherited associations, in the same order in which they appeared in the parent
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
100
File System Details
OS X File System Security
Therefore, any explicitly specified ACEs take precedence over all inherited ACEs. For more information on how
ACEs are evaluated, see Evaluating Access Control Lists (page 98).
Because ACEs can be inherited, administrators can control the fine-grained permissions of files created in a
directory by assigning inheritable ACEs to the directory. Doing so saves the work of assigning ACEs to each
file individually. In addition, because ACEs can apply to groups of users, administrators can assign permissions
to groups rather than having to specify permissions for each individual. Applying access security to directories
and groups rather than to files and individuals saves administrator time and gives better file system performance
in many circumstances.
For app programmers, the automatic inheritance of ACEs greatly simplifies working with file permissions. You
do not need to create an ACL every time you create a new file. You also don’t need to maintain inherited ACEs
when saving files. Instead, the kernel automatically creates the ACL for every new file using inherited ACEs.
Note that assignment and inheritance of BSD permissions are not affected by ACLs. If ACLs are not supported,
the BSD permissions are used. For more information on the way permissions are evaluated when both ACLs
and BSD permissions are set, see Security Schemes (page 96).
In OS X Server v10.4, the server administrator can perform the following operations:
● Copy permissions from a parent directory to all files and directories below it in the hierarchy. This makes
permissions uniform in the directory tree and should be used only for BSD permissions.
● Propagate permissions from a parent directory to all files and directories below it in the hierarchy. In this
case, explicitly specified ACEs are unchanged and ACEs inherited from them are unchanged. Files and
subdirectories inherit ACEs as if they had been newly created in place under the directories that have
explicitly specified ACEs, as illustrated in Figure B-1.
● Apply inheritance from a parent directory to a specific directory or file.
● Make inherited ACEs in directories explicit.
● Remove all ACEs from directories and files.
● Enable or disable ACLs on a volume.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
101
File System Details
OS X File System Security
The server GUI cannot directly manipulate ACEs of files. There is no GUI in the Finder to set or change ACEs.
ACEs can be read and set both on the server and client using the command-line tools ls and chmod.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
102
File System Details
OS X File System Security
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
103
File System Details
OS X File System Security
UF_NODUMP 0x1 Do not back up the file when using the UNIX dump
nodump command. This flag is largely superfluous in OS X.
This flag can be changed by either the file’s owner or
the superuser (root).
UF_APPEND 0x4 Software can only append to the file, not modify the
uappnd or uappend
existing data.
This flag can be changed by either the file’s owner or
the superuser (root).
UF_HIDDEN 0x8000 Hint that the file should be hidden in the GUI.
hidden This flag can be changed by either the file’s owner or
the superuser (root).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
104
File System Details
OS X File System Security
SF_APPEND 0x40000 Software can only append to the file, not modify the
sappnd or sappend
existing data.
This flag can be changed only by the superuser (root).
Note: To disable a flag with chflags, add no before the flag name or drop the leading no, as
appropriate.
UNIX Permissions
Each file system object has a set of UNIX permissions defined by three attributes:
● UID, short for user ID. Commonly referred to as the File’s Owner .
● GID, short for group ID.
● Flags that include permission bits and other related attributes.
The flags for a file or directory are a 16-bit value that is often represented as a three-digit or four-digit octal
value (with the top four or seven bits dropped):
● Bits 12–15: Flags indicating the type of the file. These bits are immutable and are omitted when representing
permissions.
● Bits 9–11: Special permissions bits described in Table B-4 (page 106). Usually 0; may be omitted if not set.
● Bits 6–8: Owner rights bits. These bits limit access by any process whose effective user ID (EUID) is equal
to the UID of the file or directory).
These bits have the highest precedence.
● Bits 3–5: Group rights bits. These bits limit access by any process with an effective group ID (EGID) matching
the GID of the file or directory.
These rights do not apply to any process whose EUID matches the UID of the file or directory. These bits
have lower precedence than the Owner rights, but higher precedence than the Other rights.
● Bits 0–2: Other rights bits. These bits apply to any process that matches neither the UID nor GID of the file
or directory.
The Owner, Group, and Other bit sets contain three bits: read, write, execute (rwx for short). The effect of these
bits differs for files and directories, as shown in Table B-3.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
105
File System Details
OS X File System Security
read Can open file for read Can list directory contents
write Can open file for write Can modify directory contents (move, rename, or
delete enclosed files or directories)
execute Can treat file as a program to run Can search through the directory (to access files or
directories inside it)
In addition to the r, w, and x bits, each file system object also has three ancillary permission bits: setuid,
setgid, and sticky.
setuid For a binary executable, when executed, the EUID The UID of any file or directory
of the resulting process is set to the file’s UID created within the directory is set to
instead of the EUID of the parent process. the UID of the directory.
The RUID of the resulting process is still set to the
EUID of the parent process as usual.
This flag has no effect for interpreted scripts or
non-executable files.
setgid For a binary executable, when executed, the EGID The GID of any file or directory
of the resulting process is set to the file’s GID created within the directory is set to
instead of the EGID of the parent process. the GID of the directory.
The RGID of the resulting process is still set to the
EGID of the parent process as usual.
This flag has no effect for interpreted scripts or
non-executable files.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
106
File System Details
OS X File System Security
For example, if the owner of a binary executable file is the root user and the setuid bit is set, the program
always runs with an EUID of 0. Because such a program runs with root privileges when executed by someone
other than root, it can create a security vulnerability. Therefore, it is important to restrict the creation and use
of setuid and setgid programs.
A user can change the permissions only on files owned by that user. Therefore, only the root user can set the
setuid bit on a program owned by root.
UNIX permissions are visible to users in Terminal and in the Finder. In Terminal, they look like this:
The format of the permissions (at left) is described further in Shell Script Security in Shell Scripting Primer .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
107
File System Details
OS X File System Security
In the Finder, UNIX permissions take the form of the Ownership and Permissions information in a file or folder’s
Info dialog (Figure B-3).
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
108
File System Details
OS X File System Security
A major difference between standard BSD permission semantics and the OS X implementation is that in OS X
the root user is disabled after system installation. In most cases, it is not necessary for an administrator to run
as root (see The Admin Group (page 110)). You may also assume root power by using the sudo utility. Although
the sudo utility does not require you to enable the root user, you can use it only from the Terminal app; that
is, you must have physical access to the machine to use it. See the sudo man page for more information on
its use.
The root user should not be enabled on user systems. If your app needs to perform operations as the root user,
you must use Authorization Services. For more information, see Authorization Services C Reference and
Authorization Services Programming Guide in Security Documentation.
Note: In almost all cases you can run as a member of the admin group or use sudo rather than
enabling the root user. If you absolutely must enable the root user, run the NetInfo Manager utility
and authenticate yourself as the local administrator. Then choose Enable Root User from the Security
menu. This menu item is enabled only if you are a member of the local admin group—a group with
special administrative privileges—and you have been previously authenticated in the local domain.
Once you’ve enabled the root user, the password is blank, so you should give the root user a password
by selecting Change Root Password from the Security menu. After you’ve completed the task requiring
root access, you should relinquish root user privileges by choosing Disable Root User from the
Security menu.
Whereas most user permissions apply across networks, setuid and setgid are often ignored on network
volumes, as is the concept of a root user.
For example, when accessing remote volumes over NFS, by default, the root user is mapped to nobody—a
special user with very little access. This prevents the root user on one computer from becoming the root user
on another computer.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
109
File System Details
OS X File System Security
In OS X v 10.3 and later, the wheel group is not used. Its functions have been assumed by the admin group.
The user who installs OS X on a system becomes automatically the first administrator for the system. Thereafter,
this user (or any other administrator) can use Accounts preferences to create accounts on the local system for
new users and can grant administrative privileges to any user on the system.
AFP
If the AppleShare client and server both support AFP 3.0, the actual BSD permissions are transported over the
connection. If the file or directory on the AFP server has an ACL, the ACL is transported over the connection
and the effective permissions are displayed by the Finder. However, enforcement of permissions is done only
on the server, not on the client. See POSIX ACLs (page 96) for more information on the OS X implementation
of ACLs.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
110
File System Details
OS X File System Security
If the connection is using AFP 2.x, be aware of the differences in how permissions work:
● BSD supports permissions on files, whereas AFP 2.x does not.
● BSD implements a “best match” permissions policy. If you’re the owner, you get the owner permissions.
If you’re not the owner but you’re in the file’s group, you get the group permissions. Otherwise you get
the other permissions. AFP implements a cumulative permissions policy: your permissions are the union
of the permissions you derive from the owner, group, and other permissions. For example, if a folder is
writable by the group but not by the owner, AFP permissions let the owner modify the folder but BSD
permissions do not.
● BSD interprets the rwx bits for folders as shown in Table B-3. AFP permissions define them as “See Files”,
“See Folders”, and “Make Changes”. When dealing with an AppleShare 2.x server, the OS X AppleShare
client maps between these privilege models. A similar mapping applies when you connect to an OS X
server using an AppleShare 2.x client.
● ACLs are not supported by AFP 2.x.
AFP excludes a process having an EUID of 0 (that is, one running as root) from accessing any data over the
network.
NFS
In general, NFS is not a secure protocol, because most NFS servers trust their clients. That is, if a client says that
this file operation is done on behalf of user Bob, the server does the operation on behalf of user Bob. However,
if you have root access on the client, you can pretend to be user Bob and access any of Bob’s files on the NFS
server. To maintain some security, most NFS servers map the root user to a special user, nobody, which owns
no files or directories. For this reason, if your EUID is 0 you can, in general, access only those files on an NFS
server that allow access to “other”.
SMB/CIFS
SMB is a networking protocol for file sharing commonly used on Windows networks. CIFS is often used as a
synonym for SMB. Samba is software that implements an SMB/CIFS server on UNIX. Therefore, this file sharing
protocol is variously referred to as SMB, CIFS, SMB/CIFS, Samba, and Windows file sharing.
OS X v10.4 and later implements SMB/CIFS-compatible access control lists (ACLs). Although individual users
cannot set or alter ACLs, server administrators can do so. (Administrators can use the SMB server command
line to manipulate ACLs, but only if both the client and server are bound to the same Active Directory domain.)
However, enforcement of permissions is done only on the server, not on the client. See POSIX ACLs (page 96)
for more information on the OS X implementation of ACLs.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
111
File System Details
iOS File System Security
For OS X v10.3 and earlier, all of the SMB access controls in OS X are implemented on the server, not the client.
Consequently, when an OS X user mounts an SMB file server, the volume, directory, or file mounted appears
in the Finder to allow read, write, and execute access and to be owned by the user. However, when the user
attempts to open a folder or file, the server evaluates the user’s access permissions and either allows access
or prompts the user for a new user name and password before granting access.
For more information on SMB/CIFS permissions and to learn how to modify their behavior, see the man page
for SMB (man 5 smb.conf).
WebDAV
The WebDAV protocol is an extension to the HTTP protocol that allows users to write and edit web content
remotely; that is, over a network connection. The OS X WebDAV file system uses WebDAV and HTTP requests
to access resources on a WebDAV-enabled HTTP server as files and directories.
The WebDAV protocol does not support users and groups. Furthermore, a WebDAV client cannot determine
access permissions for files and directories on a WebDAV server before attempting to access them. Therefore,
the WebDAV file system in OS X sets the user and group IDs to unknown for all files and directories and the
permissions default to read, write, and execute for everyone: user, group, and other.
When the WebDAV file system sends a request to a WebDAV-enabled HTTP server, the server determines
whether authorization is required. If no authorization is required, the server accepts the request. If authorization
is required, the server checks for authentication credentials (such as a user name and password) and, if they
are present and correct, the server authorizes the client and allows access. If authorization is required and no
credentials were sent or the credentials are not correct, the server rejects the request with a challenge for
authentication. If the user cannot supply the correct credentials, the WebDAV file system refuses access.
For more information on the protocols used by the WebDAV file system, see the following documents:
● Hypertext Transfer Protocol—HTTP/1.1 http://www.ietf.org/rfc/rfc2616.txt
● HTTP Authentication: Basic and Digest Access Authentication http://www.ietf.org/rfc/rfc2617.txt
● HTTP Extensions for Distributed Authoring—WEBDAV http://www.ietf.org/rfc/rfc2518.txt
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
112
File System Details
iOS File System Security
In addition, if file protection is enabled on an iOS device, apps can choose to prevent access to specific files to
when the device is locked. You might do this for files that contain private user data or sensitive information.
As with the keychain, encrypted files in iOS are also encrypted in any backups of the mobile device. In addition
to enabling encryption, you can also cause a file to be excluded from appearing in backups entirely.
Important: Any app that supports file protection must be prepared to handle situations in which the app
is running but the protected file is unavailable.
For more information about file protection APIs, see the information in Advanced App Tricks in App Programming
Guide for iOS .
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
113
Document Revision History
Date Notes
2012-03-08 Corrected a statement about where iOS apps can create new directories.
2012-03-01 Added a note in the Overview about changes to file system behavior when
you adopt App Sandbox in an OS X app.
2011-06-06 New document that describes how to create and manage files, directories,
and other content in the file system.
2014-09-17 | Copyright © 2014 Apple Inc. All Rights Reserved. Apple Confidential Information.
114
Apple Inc.
Copyright © 2014 Apple Inc.
All rights reserved.