Applications on OS X and iOS - Swift Development with Cocoa (2015)

Swift Development with Cocoa (2015)

Chapter 3. Applications on OS X and iOS

As far as users are concerned, applications are the only thing on their computers besides their files. After all, a computer is defined by what it can do for the user, and what it can do is defined by the applications that are installed.

As a developer, it’s easy to get drawn into the details of how an app is put together—the individual classes, methods, and structures. However, the application as a whole is what’s sold to the user, and that’s all users care about.

In this chapter, you’ll learn how applications are structured on OS X and iOS, how they differ from other kinds of distributable code, what they can do on the system, and what they’re prevented from doing by the built-in security measures provided by the OS.

What Is an Application?

Applications on iOS and OS X are packaged differently from applications on other platforms, most notably Windows. On other platforms, the end result of compiling your project is a binary file that contains the compiled code. It’s then up to you as a developer to package that binary file up with the resources it needs. On Linux, you generate a package file (which can vary depending on the distribution you’re using), and on Windows, it’s traditional to create an “installer,” which is an additional application that unpacks the binary and resources.

OS X and iOS take a different approach to applications. This approach stems from the concept of a “package”—a folder that contains a number of items but is presented to the user as a single file. Many document formats use packages as a convenient way to store and organize their data, because storing different chunks of data as separate files means that the program doesn’t have to implement logic that unpacks a single file.

NOTE

If you’re coming from a Linux background, note that “package,” in this context, means something different. A package file is just a folder that’s presented as a single file, while on Linux “package” means a redistributable file used to install software. OS X also uses the word “package” in this way—you can generate .pkg files that contain software, which when opened install the software onto your machine. When you upload an app to the Mac App Store, for example, you upload a package.

And just to add to the confusion, the Cocoa framework doesn’t call folders that are presented as single files “packages,” but rather calls them “bundles.”

Applications, therefore, are actually folders that contain the compiled binary, plus any resources they may need. The structure of applications differs slightly between OS X and iOS, but the fundamental philosophy of how an application is packaged remains the same. You can take a look inside an application by right-clicking one in the Finder and choosing Show Package Contents.

When you compile a project in Xcode and generate an application, Xcode creates the application package, and copies in any necessary resources. If you’re creating a Mac application, you can then just zip it up and send it to anyone for them to run it. On iOS, it’s a little different, because apps must be code-signed and provisioned before being run on the device.

One advantage to this is that applications are entirely self-contained and can be moved anywhere on a Mac.

NOTE

Because applications can be moved, it used to be commonplace to add code to an application that detected if the app was not in the Applications folder and offered to move itself there to keep the user’s Downloads folder tidy.

This is less common in the days of the App Store, which installs all applications directly into the Applications folder. However, if your application is being distributed by means other than the Mac App Store, it’s worthwhile to include this logic anyway.

Applications, Frameworks, Utilities, and More

Applications aren’t the only products that you can produce from Xcode. You can also generate frameworks, which are loadable bundles of code and resources that other applications (including your own) can use. Frameworks are actually very similar to applications in structure—they contain a binary file and any resources—but they’re not standalone and are designed to be used by other apps.

One prime example of a framework is AppKit.framework, which is used by every Mac application. On iOS, the equivalent framework is UIKit.framework.

NOTE

“Cocoa” is the term used by Apple to refer to the collection of libraries used by applications on OS X. On iOS, the equivalent term is “Cocoa Touch,” as it’s adapted for touchscreen devices.

What Are Apps Composed Of?

In order to function as an application on iOS or OS X, an application must have two things at a minimum:

§ The compiled binary

§ An information file describing the app to the system

The compiled binary is simply the end result of Xcode compiling all of your source code and linking it together.

Information describing the app to the system is saved in a file called Info.plist. Among other things, Info.plist contains:

§ The name of the application’s icon file

§ What kinds of documents the application can open

§ The name of the compiled binary

§ The name of the interface file to load when the application starts up

§ What languages the application supports (such as French, English, etc.)

§ Whether the application supports multitasking (for iOS apps)

§ The Mac App Store category the application is in (for OS X apps)

Info.plist is really important—in fact, if you remove it from the application bundle, the app can’t launch.

Applications also contain every resource that was compiled in—all the images, files, sounds, and other items that were added to the project via Xcode. The application can refer to these resources at runtime.

You can take a look at the structure of an OS X application by following these steps:

1. Open Xcode, and create a new OS X application. Don’t bother changing any settings when Xcode asks—just name the app whatever you like and save it somewhere.

2. Build the application. Press ⌘-B, or choose Product→Build.

3. Open the Products group in the project navigator. It will now contain the .app, which is the end result of the build process. Right-click it and choose Show in Finder. The Finder will open, revealing where Xcode put the app.

4. Right-click the application and choose Show Package Contents. The Finder will show the contents of the bundle.

The structures of OS X and iOS application bundles are different: on iOS, everything is contained at the root of the package’s folder, but on OS X, the structure is more rigorous.

The structure of a Mac application named MyApp looks like this:

MyApp.app

The top level of the package

Contents

A folder that contains the application itself

Info.plist

The file that describes the application to the system

MacOS

A folder that contains the app’s compiled binary

MyApp

The app’s compiled binary

PkgInfo

A legacy file that describes the app’s maker and what the app is

Resources

A folder that contains all of the compiled-in resources

The structure of an iOS application named MyApp looks like this:

MyApp

The app’s compiled binary

Info.plist

The file that describes the application to the system

Default.png

The image that is shown while the app is launching

Default@2x.png

The double-resolution version of Default.png, used on certain high-resolution devices (e.g., the iPhone 6 or the iPad Air)

Default@3x.png

The triple-resolution version of Default.png, used on higher resolution devices (e.g., the iPhone 6 Plus)

Embedded.mobileprovision

The provisioning profile that identifies the app as able to run on a device

Entitlements.plist

A file that describes what the application may or may not do

Because your application could be anywhere on the system, your code can’t use absolute paths to determine the location of resources. Thankfully, Cocoa already knows all about packages and how to work with them.

Using NSBundle to Find Resources in Applications

As far as your code goes, your application works the same regardless of which platform it’s running on, thanks to a useful class called NSBundle. This class allows your code to know where it is on the disk and how to get at the compiled resources.

This is especially important for iOS applications, as these apps are placed in arbitrary folders by the OS when they’re installed. This means that your code cannot depend upon being in a single place, and you can’t hardcode paths. Of course, doing that is a bad idea anyway, but on iOS, it’s guaranteed to cause failures.

You can use NSBundle to determine the location of the application’s package on disk, but most of the time you only need to know about the location of the individual resources.

NSBundle allows you to determine both URLs and plain file paths for resources on the disk. All you need to know is the name and type of the resource.

For example, the following code returns an NSString that contains the absolute path for a resource called SomeFile.txt:

let resourcePath = NSBundle.mainBundle()

.pathForResource("SomeFile", ofType: "txt")

// resourcePath is now a string containing the

// absolute path reference to SomeFile.txt, or nil

Note that this code snippet calls NSBundle.mainBundle()—it’s possible to have more than one bundle around. Remember that Cocoa refers to packages (i.e., folders containing app resources) as bundles.

You can also get URLs to resources as well:

let resourceURL = NSBundle.mainBundle()

.URLForResource("SomeFile", withExtension: "txt")

// resourceURL is now an NSURL, or nil

This method looks inside the Resources folder in the application bundle for the named file. (On iOS, it looks inside the root folder of the application bundle.)

Absolute paths and URLs are functionally the same when referring to files stored on disk, but using URLs is preferred—a string could theoretically contain anything, whereas a URL always points to a location. This includes file URLs, which look like this: file:///Applications/Xcode.app/. You can therefore use URLs in any case where you’d normally use a file path.

If you add an image or other resource to your project, it is copied into the application bundle when the project is built. For Mac apps, the resources are copied into the Resources folder, and for iOS apps, the resources are copied into the root folder of the application.

The Application Life Cycle

Every program starts, runs, and quits. What’s interesting is what it does in between. For the most part, applications on OS X and iOS behave similarly, with the exception that iOS handles multitasking in a different way from standard desktop applications.

In this section, we’ll walk through the life cycle of both kinds of applications, and discuss what happens at various stages of an app’s life.

OS X Applications

When an application is launched, the first thing the system does is open the application’s Info.plist. From this file, the system determines where the compiled binary is located, and launches it. From this point on, the code that you write is in control.

In addition to the compiled code, applications almost always have a collection of objects that were prepared at design time and bundled with the application. These are usually interface objects—pre-prepared windows, controls, and screens—which are stored inside a nib file when the application is built. When the application runs, these nib files are opened, and the premade objects are loaded into memory.

NOTE

For more information on nib files, as well as the related storyboards and how they’re built, see Chapter 4.

The first thing an application does is open the nib file and deserialize its contents. This means that the application unpacks the windows, controls, and anything else stored in it and links them together. The main nib also contains the application delegate object, which is unpacked with all the rest.

When an object is unpacked from a nib, it is sent the awakeFromNib message. This is the moment at which that object can begin to run code.

NOTE

Objects that are unpacked from a nib are not sent an init message because they were already initialized when the developer dragged and dropped them into the interface. This is different from objects that are created by calling their constructor in code.

When working with nib files, it’s important to understand that when you add an object to a nib file, that object is created at that moment, and “freeze-dried” when the nib file is saved. When the nib file is opened, the object is “rehydrated” and gets back to work. After the object is rehydrated, it is sent the awakeFromNib message to let it know that it’s awake.

To summarize: objects that are loaded from a nib receive the awakeFromNib message. Objects that are created by your code receive the init method.

At this point, the application is ready to start running properly. The first thing it does is to send the application delegate the applicationDidFinishLaunching method. After that method completes, the application enters the run loop.

The run loop continues looping until the application quits. The purpose of the run loop is to listen for events—keyboard input, mouse movement and clicks, timers going off, etc.—and send those events to the relevant destinations. For example, say you have a button hooked up to a method that should be run when the button is clicked. When the user clicks the button, the mouse-click event is sent to the button, which then causes its target method to get run.

On OS X, applications continue to run when the user selects another app. When the user changes applications, the application delegate receives the applicationWillResignActive message, indicating that the application is about to stop being the active one. Soon after, the app delegate receives the applicationDidResignActive method.

The reason these two methods are separate is to let your code manage what happens to the screen’s contents when the home button is tapped on iOS, or when the user switches to another app on OS X. When applicationWillResignActive is called, your application is still present on the screen. When the application is no longer visible, the application delegate receives applicationDidResignActive.

When the user comes back to the app, the application delegate receives a pair of similar methods: applicationWillBecomeActive and applicationDidBecomeActive. These are sent immediately before and after the application returns to being the active one.

The event loop is terminated when the application quits. When this happens, the application delegate receives the applicationWillTerminate message, which is sent immediately before the app quits. This is the last opportunity an app has to save files before quitting.

iOS Applications

iOS applications behave in a broadly similar manner to OS X applications, with a few differences. The main one is that iOS applications are presented differently from desktop apps, and the tighter memory constraints on an iOS device mean that there are more stringent rules about multitasking.

On iOS, only one application is on the screen at a time—any other applications are completely hidden. The visible application is known as the foreground application, and any apps also running are background applications. There are strict limits on how long an application may run in the background, which we’ll discuss shortly.

When using an application on iOS, a user may be interrupted by something else—an incoming phone call, for example—which replaces the app with which the user was interacting. The application is still technically considered to be in the foreground, but it is now inactive. If the user accepts the phone call, the phone application becomes the foreground application, and the previous app moves to the background.

There are other methods by which an application can become inactive, such as when the user pulls down the notifications tray (by swiping down from the top of the screen), or opens the task switcher (by double-tapping on the home button). When an application becomes inactive, it’s a signal that it may be exited, so your app should make sure to save any work.

The iOS application life cycle is almost identical to that of an OS X application. When the app is launched, the Info.plist file is checked, the compiled binary is found and loaded, and the application begins running code, starting by unpacking the contents of the main storyboard.

When the application completes loading, the application delegate receives the applicationDidFinishLaunching(_, withOptions:) method. This is similar to the OS X counterpart, but adds an additional parameter—a dictionary, which contains information about why and how the application was launched.

Applications are most commonly launched directly by the user tapping on the icon. They can also be launched by other applications, such as when an app passes a file to another or is opened through a custom URL. The options dictionary contains information that describes the circumstances under which the application launched.

Just as with OS X applications, iOS applications also receive applicationWillResignActive and applicationDidBecomeActive messages (with one difference—on OS X, the parameter to these methods is an NSNotification object, whereas on iOS the parameter is aUIApplication).

When an application is quit by the user on OS X, we have seen that the application delegate receives the applicationWillTerminate method. This was also the case for iOS applications, until iOS 4. At this point, multitasking was introduced, and the life cycle of iOS applications changed.

Multitasking on iOS

Applications on iOS are permitted to run in the background, but only under certain very limited conditions. That’s because iOS devices are much more constrained than OS X devices in the areas of CPU power, memory space, and battery capacity. A MacBook Pro is expected to run for around 7 hours on battery, with a full set of applications (e.g., a word processor, web browser, etc.) loaded and running. An iPhone 6 Plus, by contrast, is expected to last for greater than 8 hours on WiFi while browsing the Internet—on a battery with a fraction of the capacity of a full-size laptop battery. Additionally, a MacBook Pro (at the time of writing) ships with 8 GB of memory, while an iPhone 6 Plus has only 1 GB, and an iPad Air 2 has only 2 GB.

There’s simply no room to fit all the applications at once, so iOS is forced to make some decisions about what applications can run in the background and for how long.

When an application exits (e.g., when the user hits the home button or another application launches), the application is suspended—it hasn’t quit, but it stops executing code and its memory is locked. When the application resumes, it simply picks up where it left off.

This means that the application remains in memory, but stops consuming the system’s power-draining resources such as the CPU and location hardware. However, memory is still tight on the iPhone, so if another app needs more memory, the application is simply terminated without notice.

Note that an application that is suspended doesn’t get to run any code, and therefore can’t get notified that it’s being terminated while suspended. This means that any critical data must be saved when the application delegate is told that the application is being moved to the background.

Applications are not told when they are suspended or when they are woken up. They are told when they move into and out of the background, however, through the following delegate methods:

func applicationDidEnterBackground(_ application: UIApplication)

and

func applicationWillEnterForeground(_ application: UIApplication)

applicationDidEnterBackground is called immediately after the application has moved to the background state. The application will be suspended after the method has run, which means that the app needs to save any data it’s working on because it may be terminated while suspended.

applicationWillEnterForeground is called just before the application comes back on screen, and is your application’s opportunity to get set up to work again.

As mentioned earlier, applications that are suspended are candidates for termination if the new foreground app needs more memory. As an application developer, you can reduce the chances of this happening by reducing the amount of memory your application is using—by freeing large objects, unloading images, and so on.

NOTE

If possible, try to reduce the amount of memory being used to under 16 MB. When the application is suspended and the memory usage is under 16 MB, the system will store the application’s memory on the flash chips and remove it from memory entirely. When the application is resumed, the application’s memory state is reloaded from the stored memory on the flash chips—meaning that the application won’t be evicted from memory due to another application’s memory demands. We’ll look at how to measure memory usage in Fixing Problems Using Instruments.

An application can request to run in the background for a short period of time. This background period can be no longer than 10 minutes, and it exists to allow your application to complete a long-running process—writing large files to disk, completing a download, or some other lengthy process. At the end of the 10 minutes, your application must indicate to the OS that it is done or it will be terminated (not suspended, but terminated—gone from memory completely).

To run tasks in the background, you need to add code that looks like this to your application delegate:

func applicationDidEnterBackground(application : UIApplication) {

var backgroundTask : UIBackgroundTaskIdentifier! = nil

// Register a background task, and provide a block to run when

// time runs out

backgroundTask = application

.beginBackgroundTaskWithExpirationHandler() {

// This block is called when we're out of time; if we haven't

// called endBackgroundTask before this block returns,

// the application is terminated

application.endBackgroundTask(backgroundTask)

backgroundTask = UIBackgroundTaskInvalid

}

let backgroundQueue = NSOperationQueue()

backgroundQueue.addOperationWithBlock() {

// Do some work. You have a few minutes to complete it; by the end,

// you must call endBackgroundTask.

NSLog("Doing some background work!")

application.endBackgroundTask(backgroundTask)

backgroundTask = UIBackgroundTaskInvalid

}

}

There is no guarantee that the extra time to perform background tasks will be in one contiguous chunk; the time may be broken up into multiple chunks to improve battery life. Introduced with iOS 7 were two means of running tasks in the background: background fetching and background notifications.

Background fetching is designed for applications that require periodic updates, such as weather applications or social networking applications like Twitter. With background fetching enabled, an application can be woken up in the background to retrieve up-to-date information in the background to have ready to immediately display when the user brings the application to the foreground.

To use background fetching, there are a few things you need to do:

§ Select the project in the project navigator, open the Capabilities tab, and enable Background Fetch from the Background Modes section.

§ In your code, you need to call the setMinimumBackgroundFetchInterval function to let iOS know approximately how often to wake your application so it can fetch updates. If you do not set a minimum interval, iOS will default to never waking your application for performing fetches.

To actually perform the fetching when iOS wakes your application, you will have to add code to your application delegate that looks like this:

func application(application: UIApplication,

performFetchWithCompletionHandler completionHandler:

(UIBackgroundFetchResult) -> Void) {

// We have 30 seconds to download some data and process it

var error : NSError? = nil

let data = downloadSomeData(&error)

// Once done, let the OS know whether or not new data was

// retrieved or not, or if there was an error

if error != nil {

completionHandler(UIBackgroundFetchResult.Failed)

return

}

// This is a very simple check—your application would

// do something more involved, like compare this data against

// the most recently downloaded data to determine if it's 'new'

if data?.length > 0 {

completionHandler(UIBackgroundFetchResult.NewData)

return

} else {

completionHandler(UIBackgroundFetchResult.NoData)

return

}

}

Background notifications allow your application to receive notifications and process them in the background. Background notifications could be used in an instant messaging application to automatically update the conversation while the application is in the background or to alert your application when new content is available to be fetched.

Background notifications operate in a manner very similar to background fetching, and require a similar setup before being available for use in your application. Your application will need to be able to handle notifications, which are discussed in Notifications, and you’ll need to enable remote notifications in your project.

To enable remote notifications, select the project in the project navigator, open the Capabilities tab, and enable “Remote notifications” from the Background Modes section.

Much like background fetch, an application method that handles the notifications is called whenever your application receives a notification. The code to receive this notifications looks like this:

func application(application: UIApplication,

didReceiveRemoteNotification userInfo: [NSObject : AnyObject])

This method functions in a manner very similar to the method for handling background fetching and even requires the same results to be passed into the callback handler when completed. The main difference is the userInfo parameter, which is a dictionary containing the data that the remote notification contained.

WARNING

Keep in mind that despite letting you set a minimum interval for fetching in the background, iOS will wake your application at what it determines is the best time without causing unnecessary drain on the device’s battery. In a similar manner, Apple will limit how many remote notifications are sent to the device for the same reasons. If your application isn’t behaving exactly as you set it, this might be the cause.

There are other cases in which an application can run in the background for longer periods of time, all of which are geared toward more specialized applications:

§ Applications that play audio in the background can remain active for as long as they like, until the user starts playing audio from another app. For example, the Pandora Internet radio app can run in the background until the user starts playing music from the Music application.

§ Applications that track the user’s location in the background can run for as long as they like.

§ Voice over IP (VoIP) applications like Skype are allowed to run periodically to check in with their server, but aren’t allowed to run indefinitely except when a call is active.

In summary, if you’re writing an application for iOS, you can only expect to be running on the device when the user is directly accessing your app. When the user can’t see your application, it quite literally becomes a case of “out of sight, out of mind.”

The Application Sandbox

OS X and iOS implement a number of features to improve the overall level of security for the user. One of these features is the application sandbox, a tool that restricts what an application is allowed to do. The application exists inside the sandbox, and may not try to access any system resources (hardware, user data, etc.) that is outside the sandbox. Sandboxes are somewhat optional for Mac applications, and mandatory for iOS applications.

A sandbox improves the security of the system by preventing an app from doing something that either Apple or the user does not want it to do. This is specifically useful for improving the security of apps, because the majority of hacks take the form of exploiting a bug in an existing application. Adobe’s Acrobat Reader and Microsoft’s Internet Explorer 6 are two applications through which malicious people have been able to compromise other users’ systems (install extra software, retrieve private data, etc.). These exploits take the form of modifying the compromised application to make it perform the intruder’s bidding.

Sandboxes solve this problem by preventing (at a kernel level) an application from accessing user data, communicating with the network, accessing hardware like the camera and microphone, and so on. Even if the software has an exploitable bug, the intruder cannot access user data because the application is not permitted to reach outside of its sandbox.

Applications that are downloaded from the iOS App Store are automatically placed in a sandbox; we will discuss this in more detail in Working with the Sandbox. Applications that are distributed via the Mac App Store require being sandboxed as well; however, apps that you distribute yourself do not.

Application Restrictions

As mentioned earlier, a sandbox restricts what an application can do. The restrictions vary significantly between iOS and OS X, because applications on OS X have traditionally been less restricted in terms of what they’re allowed to do.

For example, a Mac application can request read/write access to any of the user’s files. An iOS application can only work with its own documents, and can’t open any files outside of its sandbox.

iOS application restrictions

When an iOS app is installed on the device, it’s given a container to store its information in. This folder contains the following items:

Documents

Stores all documents belonging to the application

Library

Stores all settings and configuration info

Caches

Contains data that is useful to have on disk, but could be regenerated; items in this folder are deleted by the system if it needs to free some space

Preferences

Stores settings and preferences

tmp

Stores files temporarily; items in this folder are periodically deleted by the system

An iOS application is not allowed to work with any file outside of its folder. This prevents the bundle from reading private information (like phone call logs) or modifying any system files.

Mac application restrictions

The idea of putting restrictions on what Mac apps can do only arrived with the release of the Mac App Store in 2011, which means that Apple had quite a bit of time to figure out how to implement it.

When you decide to make your application sandboxed, Xcode presents you with a number of options that determine what your application is allowed to do. These options are called entitlements.

The available entitlements that your Mac application can request are:

Filesystem

You can determine whether the application has read/write, read-only, or no access to the filesystem. You can also control whether the application can work with certain folders, such as the Downloads folder.

Network

You can determine whether the application is allowed to make outgoing connections and accept incoming connections.

Hardware

You can determine whether the application is allowed to access the built-in camera and microphone, communicate with devices via USB, and print.

App communication

You can determine whether the application is allowed to work with the data managed by the Address Book or Calendar, and whether it is allowed to work with the user’s location information.

Music, movies, and pictures folder access

You can determine whether the application can work with the user’s music, photos, and movies by controlling whether the app has read/write, read-only, or no access to these folders. You can set each folder’s access permissions separately.

Private APIs

One of the rules that Apple imposes on applications that are sold via the iTunes App Store or the Mac App Store is that apps are only allowed to communicate with the system via the classes and methods that Apple has documented and indicated as being for developer use.

There are many “private” classes and methods that Apple uses behind the scenes. For example, the code that determines whether an iOS device is locked with a passcode is undocumented; Apple uses it (such as in the Find My Friends app), but developers like us may not.

Apple scans all submitted applications as part of the App Store review process. This happens automatically, before a human being sits down to review your application. If your application is rejected for using a private API, you must remove the private API usage and resubmit. If Apple notices that your app uses private APIs after the app has gone live in the App Store, they’ll simply take down the app.

The point is clear: Apple does not like developers using undocumented APIs. This is because documented APIs are known by Apple to be safe and (mostly) bug-free. Documented APIs are also features that Apple has committed to, and won’t change underneath you. Undocumented APIs, on the other hand, are often still under active development, or may provide access to parts of the OS that Apple considers out of bounds for app developers.

Notifications with NSNotification

It’s often useful to broadcast notifications to any interested application when something of relevance happens. For example, when the user presses the home button on an iOS device, the only object that receives a notification by default is the application delegate, which receives theapplicationDidEnterBackground message. However, objects in the application may wish to be notified of events like this, and while it’s possible for the application delegate to do something like maintain an array of objects to send messages to when an app-wide event takes place, it can be cumbersome.

Enter the NSNotification class. NSNotification objects, or notifications for short, are broadcast messages sent by an object to any other object that has registered to be notified of such notifications. Notifications are managed by the NSNotificationCenter, which is a singleton object that manages the delivery of notifications.

Notifications are created by the object that wants to broadcast, or post, the notification. The NSNotification object is given to the notification center, which then delivers the notification to all objects that have registered for that notification type.

When an object wants to start receiving notifications, it first needs to know the name of the notification it wants to be told about. There are hundreds of different notification types; to continue with our earlier example, the specific notification posted when the application enters the background is UIApplicationDidEnterBackgroundNotification.

NOTE

Notification types are actually just strings, so you can also define your own notification types.

Therefore, to register for this notification, all an object needs to do is this:

// Get the notification center to use (in this and almost all

// cases, use the default center)

let notificationCenter = NSNotificationCenter.defaultCenter()

// Get the operation queue to run the notification handler on

// (in this case, the main operation queue)

let operationQueue = NSOperationQueue.mainQueue()

// Register for the notification UIApplicationDidEnterBackgroundNotification

let applicationDidEnterBackgroundObserver =

notificationCenter.addObserverForName(

UIApplicationDidEnterBackgroundNotification,

object: nil, queue: operationQueue) {

(notification: NSNotification!) in

println("Hello!")

}

The addObserverForName method returns an object, called the observer, which you need to keep around. You use this object when unregistering for notifications, like this:

notificationCenter.removeObserver(applicationDidEnterBackgroundObserver)

WARNING

If you don’t unregister for notifications, you’ll leave behind dangling notification handlers, which can cause wasted memory and crashes. Always unregister your notification handlers!

Once you’ve registered for a notification, your notification handler block will run every time the notification is fired.

You’ll notice that the handler block receives one parameter: an NSNotification object. This object contains information about the notification itself, which varies between different notification types.

You can also post your own notifications, if you’ve defined a notification type:

let MyNotificationType = "MyNotificationType"

// the 'object' parameter is the object responsible for sending the

// notification, and can be nil

notificationCenter.postNotificationName(MyNotificationType, object: nil)