As a courtesy, this is a full free rendering of my book, Programming iOS 6, by Matt Neuburg. Copyright 2013 Matt Neuburg. Please note that this edition is outdated; the current books are iOS 13 Programming Fundamentals with Swift and Programming iOS 13. If my work has been of help to you, please consider purchasing one or both of them, or you can reward me through PayPal at http://www.paypal.me/mattneub. Thank you!

Chapter 11. Cocoa Events

None of your code runs until Cocoa calls it. The art of Cocoa programming consists largely of knowing when and why Cocoa will call your code. If you know this, you can put your code in the correct place, with the correct method name, so that your code runs at the correct moment, and your app behaves the way you intend.

In Chapter 7, for example, we wrote a method to be called when the user taps a certain button in our interface, and we also arranged things so that that method would be called when the user taps that button:

- (void) buttonPressed: (id) sender {
    // ... react to the button being pressed
}

This architecture typifies the underpinnings of a Cocoa program. Your code itself is like a panel of buttons, waiting for Cocoa to press one. If something happens that Cocoa feels your code needs to know about and respond to, it presses the right button — if the right button is there. You organize your code with Cocoa’s behavior in mind. Cocoa makes certain promises about how and when it will dispatch messages to your code. These are Cocoa’s events. You know what these events are, and you arrange for your code to be ready when Cocoa delivers them.

Thus, to program for Cocoa, you must, in a sense, surrender control. Your code never gets to run just whenever it feels like it. It can run only in response to some kind of event. Something happens, such as the user making a gesture on the screen, or some specific stage arriving in the lifetime of your app, and Cocoa dispatches an event to your code — if your code is prepared to receive it. So you don’t write just any old code you want to and put it in any old place. You use the framework, by letting the framework use you. You submit to Cocoa’s rules and promises and expectations, so that your code will be called at the right time and in the right way.

The specific events that you can receive are listed in the documentation. The overall architecture of how and when events are dispatched and the ways in which your code arranges to receive them is the subject of this chapter.

Reasons for Events

Broadly speaking, the reasons you might receive an event may be divided informally into four categories. These categories are not official; I made them up. Often it isn’t completely clear which of these categories an event fits into; an event may well appear to fit two categories. But they are still generally useful for visualizing how and why Cocoa interacts with your code:

User events
The user does something interactive, and an event is triggered directly. Obvious examples are events that you get when the user taps or swipes the screen, or types a key on the keyboard.
Lifetime events
These are events notifying you of the arrival of a stage in the life of the app, such as the fact that the app is starting up or is about to go into the background, or of a component of the app, such as the fact that a UIViewController’s view has just loaded or is about to be removed from the screen.
Functional events
Cocoa is about to do something, and turns to you in case you want to supply additional functionality. I would put into this category things like UIView’s drawRect: (your chance to have a view draw itself) and UILabel’s drawTextInRect: (your chance to modify the look of a label), with which we experimented in Chapter 10.
Query events
Cocoa turns to you to ask a question; its behavior will depend upon your answer. For example, the way data appears in a table (a UITableView) is that whenever Cocoa needs a cell for a row of the table, it turns to you and asks for the cell.

Subclassing

A built-in Cocoa class may define methods that Cocoa itself will call and that you are invited (or required) to override in a subclass, so that your custom behavior, and not (merely) the default behavior, will take place.

An example I gave in Chapter 10 was UIView’s drawRect:. This is what I call a functional event. By overriding drawRect: in a UIView subclass, you dictate the full procedure by which a view draws itself. You don’t know exactly when this method will be called, and you don’t care; when it is, you draw, and this guarantees that the view will always appear the way you want it to. (You never call drawRect: yourself; if some underlying condition has changed and you want the view to be redrawn, you call setNeedsDisplay and let Cocoa call drawRect: in response.)

Built-in UIView subclasses may have other functional event methods you’ll want to customize through subclassing. Typically this will be in order to change the way the view is drawn, without taking command of the entire drawing procedure yourself. In Chapter 10 I gave an example involving UILabel and its drawTextInRect:. Another example is UISlider, which lets you customize the position and size of the slider’s “thumb” by overriding thumbRectForBounds:trackRect:value: (Chapter 25).

UIViewController (Chapter 19) is a good example of a class meant for subclassing. Of the methods listed in the UIViewController class documentation, just about all are methods you might have reason to override. If you create a UIViewController subclass in Xcode, you’ll see that the template already includes a few methods to get you started; these are all method overrides. For example, viewDidLoad is called to let you know that your view controller’s view has loaded, so you can perform initializations; it’s an obvious example of a lifetime event.

A UIViewController method like supportedInterfaceOrientations is what I call a query event. Your job is to return a bitmask telling Cocoa what orientations your view can appear in at this moment — whenever that may be. You don’t know exactly when this method will be called, and you don’t care; you trust Cocoa to call it at the appropriate moments, so that if the user rotates the device, your app will or won’t be rotated to compensate, depending on what value you return.

When looking for events that you can receive through subclassing, be sure to look upward though the inheritance hierarchy. For example, if you’re wondering how to be notified when your custom UILabel subclass is embedded into another view, you won’t find the answer in the UILabel class documentation; a UILabel receives the appropriate event by virtue of being a UIView. In the UIView class documentation, you’ll learn that you can override didMoveToSuperview to be informed when this happens.

Even further up the inheritance hierarchy, you’ll find things like NSObject’s initialize class method. Before any class is sent its first class message (including instantiation), it is sent the initialize message. Thus, initialize can be overridden in order to run code extremely early in a class’s lifetime (before it even has an instance). Your project’s application delegate class (such as AppDelegate in our Empty Window project) is instantiated very early in the app’s lifetime, so its initialize can be a good place to perform very early app initializations, such as setting default values for any user preferences. When implementing initialize, we must test, as a matter of course, whether self really is the class in question (and this is one of the few situations in which we will compare two classes directly against one another); otherwise there is a chance that initialize will be called again (and our code will run again) if a subclass of this class is used:

// MyClass.m:
+ (void)initialize {
    if (self == [MyClass class]) {
        // do stuff
    }
}

Notifications

Cocoa provides your app with a single instance of NSNotificationCenter, informally called the notification center, and available as [NSNotificationCenter defaultCenter]. This instance is the basis of a mechanism for sending messages called notifications. A notification includes an instance of NSNotification (a notification object). The idea is that any object can be registered with the notification center to receive certain notifications. Another object can hand the notification center a notification object to send out (this is called posting the notification). The notification center will then send that notification object, in a notification, to all objects that are registered to receive it.

The notification mechanism is often described as a dispatching or broadcasting mechanism, and with good reason. It lets an object send a message without knowing or caring what object or how many objects receive it. This relieves your app’s architecture from the formal responsibility of somehow hooking up instances just so a message can pass from one to the other (which can sometimes be quite tricky or onerous, as discussed in Chapter 13). When objects are conceptually “distant” from one another, notifications can be a fairly lightweight way of permitting one to message the other.

An NSNotification object has three pieces of information associated with it, which can be retrieved by instance methods:

name
An NSString which specifies the notification’s meaning.
object
An instance associated with the notification; typically, the instance that posted it.
userInfo
Not every notification has a userInfo; it is an NSDictionary, and can contain additional information associated with the notification. What information this NSDictionary will contain, and under what keys, depends on the particular notification; you have to consult the documentation. For example, the documentation tells us that UIApplication’s UIApplicationDidChangeStatusBarFrameNotification includes a userInfo dictionary with a key UIApplicationStatusBarFrameUserInfoKey whose value is the status bar’s frame. When you post a notification yourself, you can put anything you like into the userInfo for the notification’s recipient(s) to retrieve.

Receiving a Built-In Notification

Cocoa itself posts notifications through the notification center, and your code can register to receive them. You’ll find a separate Notifications section in the documentation for a class that provides them.

To register for a notification, you send one of two messages to the notification center. One is addObserver:selector:name:object:. The parameters are as follows:

addObserver:
The instance to which the notification is to be sent. This will typically be self; it isn’t usual for one instance to register a different instance as the receiver of a notification.
selector:
The message to be sent to the observer instance when the notification occurs. The designated method should return void and should take one parameter, which will be the NSNotification object (so the parameter should be typed as NSNotification* or id). Don’t forget to implement this method! If the notification center sends a notification by sending the message specified as the selector: here, and there is no method implemented to receive this message, your app will crash. Failing to specify the selector: accurately is a common beginner mistake (and the compiler doesn’t save you from yourself).
name:
The NSString name of the notification you’d like to receive. If this parameter is nil, you’re asking to receive all notifications sent by the object designated in the object: parameter. A built-in Cocoa notification’s name is usually a constant. As I explained in Chapter 1, this is helpful, because if you flub the name of a constant, the compiler will complain, whereas if you enter the name of the notification directly as an NSString literal and you get it wrong, the compiler won’t complain but you will mysteriously fail to get any notifications (because no notification has the name you actually entered) — a very difficult sort of mistake to track down.
object:
The object of the notification you’re interested in, which will usually be the object that posted it. If this is nil, you’re asking to receive all notifications with the name designated in the name parameter. (If both the name: and object: parameters are nil, you’re asking to receive all notifications!)

For example, in one of my apps I need to respond, by changing my interface, if the device’s music player starts playing a different song. The API for the device’s built-in music player belongs to the MPMusicPlayerController class (Chapter 29); this class provides a notification to tell me when the built-in music player changes its playing state, listed under Notifications in the MPMusicPlayerController’s class documentation as MPMusicPlayerControllerNowPlayingItemDidChangeNotification.

It turns out, looking at the documentation, that this notification won’t be posted at all unless I call MPMusicPlayerController’s beginGeneratingPlaybackNotifications instance method. This architecture is not uncommon; Cocoa saves itself some time and effort by not sending out certain notifications unless they are switched on, as it were. So my first job is to get an instance of MPMusicPlayerController and call this method:

MPMusicPlayerController* mp = [MPMusicPlayerController iPodMusicPlayer];
[mp beginGeneratingPlaybackNotifications];

Now I register myself to receive the desired playback notification:

[[NSNotificationCenter defaultCenter] addObserver:self
      selector:@selector(nowPlayingItemChanged:)
          name:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
        object:nil];

So now, whenever an MPMusicPlayerControllerNowPlayingItemDidChangeNotification is posted, my nowPlayingItemChanged: method will be called:

- (void) nowPlayingItemChanged: (NSNotification*) n {
    MPMusicPlayerController* mp = [MPMusicPlayerController iPodMusicPlayer];
    self->_nowPlayingItem = mp.nowPlayingItem;
    // ... and so on ...
}

The other way to register to receive a notification is by calling addObserverForName:object:queue:usingBlock:. Its name: and object: parameters are just like those of addObserver:selector:name:object:, but it doesn’t specify an observer and it doesn’t specify a selector. Instead, you provide a block — the actual code to be executed when the notification fires. There is no need to specify an observer, and there is no userInfo: parameter, because you’re providing a block: the code that will be called is this block, right here, and there can be no difficulty providing the block’s code with whatever values it needs. (This method also returns a value, whose purpose I’ll explain in a moment.)

This way of registering for a notification has some tremendous advantages. For addObserver:selector:name:object: to work properly, you must get the selector right and make sure you implement the corresponding method. With a block, there is no selector and there is no separate method; everything happens right there in the block, like this:

MPMusicPlayerController* mp = [MPMusicPlayerController iPodMusicPlayer];
[mp beginGeneratingPlaybackNotifications];
id ob = [[NSNotificationCenter defaultCenter]
 addObserverForName:MPMusicPlayerControllerNowPlayingItemDidChangeNotification
 object:nil queue:nil usingBlock:^(NSNotification *n) {
         self->_nowPlayingItem = mp.nowPlayingItem;
         // ... and so on ...
     }
 }];

Consider how maintainable and understandable that code is. Heavy use of addObserver:selector:name:object: means that your code ends up peppered with methods that exist solely in order to be called by the notification center. But there is nothing about these methods that tells you what they are for — you will probably want to use explicit comments in order to remind yourself — and the methods are separate from the registration call, all of which makes your code very method-heavy and confusing. With a block, on the other hand, the whole purpose of the registration is crystal-clear, because the block accompanies it. And notice how, in the block, I don’t have to redefine mp as I did in the separate method nowPlayingItemChanged:; it is still in scope from where it was defined a couple of lines earlier. Blocks are so convenient!

Unregistering

It is up to you, for every object that you register as a recipient of notifications, to unregister that object before it goes out of existence. If you fail to do this, and if the object does go out of existence, and if a notification for which that object is registered is posted, the notification center will attempt to send the appropriate message to that object, which is now missing in action. The result will be a crash at best, and chaos at worst.

To unregister an object as a recipient of notifications, send the notification center the removeObserver: message. (Alternatively, you can unregister an object for just a specific set of notifications with removeObserver:name:object:.) The object passed as the observer: argument is the object that is no longer to receive notifications. What object that is depends on how you registered in the first place:

You called addObserver:...
You supplied an observer originally; that is the observer you must now unregister.
You called addObserverForName:...
The call returned an observer token object, which you captured as an id variable (its real class and nature are no concern of yours); that is the observer you must now unregister.

The trick is finding the right moment to do this. The fallback solution is the registered instance’s dealloc method, this being the last lifetime event an instance is sent before it goes out of existence. If you’re using ARC and addObserverForName:..., there are memory management implications that I’ll talk about in Chapter 12.

Keep it simple, because complicated logic for registering and unregistering for notifications can be difficult to debug, especially as NSNotificationCenter provides no kind of introspection: you cannot ask an NSNotificationCenter what objects are registered with it as notification recipients. I once had a devil of a time understanding why one of my instances was not receiving a notification for which it was registered. Caveman debugging didn’t help. Eventually I realized that some code I’d forgotten about was unregistering my instance.

If you’re calling addObserverForName:... multiple times from the same class, you’re going to end up receiving from the notification center multiple observer tokens, which you need to preserve so that you can unregister by handing them back to the notification center. If your plan is to unregister everything at once, one way to handle this situation is through an instance variable that is a mutable collection. So, for example, I might have an NSMutableSet instance variable called _observers. Early on, I initialize it to an empty set:

self->_observers = [NSMutableSet set];

Each time I register for a notification using a block, I capture the result and add it to the set:

id ob = [[NSNotificationCenter defaultCenter]
    addObserverForName:@"whatever" object:nil queue:nil
    usingBlock:^(NSNotification *note) {
        // ... whatever ...
    }];
[self->_observers addObject:ob];

Ultimately, I unregister by enumerating the set:

for (id ob in self->_observers)
    [[NSNotificationCenter defaultCenter] removeObserver:ob];

The tedium of doing all that is a price worth paying in order to take advantage of blocks when using notifications.

Note

I am skipping over some other aspects of notifications that you probably won’t need to know about. Read Apple’s Notification Programming Topics for Cocoa if you want the gory details.

NSTimer

A timer (NSTimer) is not, strictly speaking, a notification; but it behaves very similarly. It is an object that gives off a signal (fires) after the lapse of a certain time interval. The signal is a message to one of your instances. Thus you can arrange to be notified when a certain time has elapsed. The timing is not perfectly accurate, but it’s pretty good.

Timer management is not exactly tricky, but it is a little unusual. A timer that is actively watching the clock is said to be scheduled. A timer may fire once, or it may be a repeating timer. To make a timer go out of existence, it must be invalidated. A timer that is set to fire once is invalidated automatically after it fires; a repeating timer repeats until you invalidate it by sending it the invalidate message. An invalidated timer should be regarded as off-limits: you cannot revive it or use it for anything further, and you should probably not send any messages to it.

The straightforward way to create a timer is with the NSTimer class method scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:. This creates the timer and schedules it, so that it begins watching the clock immediately. The target and selector determine what message will be sent to what object when the timer fires; the method in question should take one parameter, which will be a reference to the timer. The userInfo is just like the userInfo of a notification.

For example, one of my apps is a game with a score; I want to penalize the user, by diminishing the score, for every ten seconds after each move that elapses without the user making a further move. So each time the user makes a move, I create a repeating timer whose time interval is ten seconds (and I also invalidate any existing timer); in the method that the timer calls, I diminish the score.

Timers have some memory management implications that I’ll discuss in Chapter 12.

Delegation

Delegation is an object-oriented design pattern, a relationship between two objects, in which the first object’s behavior is customized or assisted by the second. The second object is the first object’s delegate. No subclassing is involved, and indeed the first object is agnostic about the second object’s class.

As implemented by Cocoa, here’s how delegation works. A built-in Cocoa class has an instance variable, usually called delegate (it will certainly have delegate in its name). For some instance of that Cocoa class, you set the value of this instance variable to an instance of one of your classes. At certain moments in its activity, the Cocoa class promises to turn to its delegate for instructions by sending it a certain message: if the Cocoa instance finds that its delegate is not nil, and that its delegate is prepared to receive that message (see Chapter 10 on respondsToSelector:), the Cocoa instance sends the message to the delegate.

Recall the discussion of protocols from Chapter 10. Delegation is one of Cocoa’s main uses of protocols. In the old days, delegate methods were listed in the Cocoa class’s documentation, and their method signatures were made known to the compiler through an informal protocol (a category on NSObject). Now, though, a class’s delegate methods are usually listed in a genuine protocol with its own documentation. There are over 70 Cocoa delegate protocols, showing how heavily Cocoa relies on delegation. Most delegate methods are optional, but in a few cases you’ll discover some that are required.

To customize a Cocoa instance’s behavior through delegation, you start with one of your classes, which, if necessary, declares conformance to the relevant delegate protocol. When the app runs, you set the Cocoa instance’s delegate ivar (or whatever its name is) to an instance of your class. You might do this in code, usually through a property; you might do it in a nib, by connecting an instance’s delegate outlet (or whatever it’s called) to an appropriate instance that is to serve as delegate. Your delegate class will probably do other things besides serving as this instance’s delegate. Indeed, one of the nice things about delegation is that it leaves you free to slot delegate code into your class architecture however you like. For example, if a view has a controller (a UIViewController), it will often make sense for the controller to serve also as the delegate of that view, and even of its subviews.

Here’s a simple example, involving UIAlertView. If a UIAlertView has no delegate, then when its Cancel button is tapped, the alert view is dismissed. But if you want to do something in response to the alert view being dismissed, you need to give it a delegate so that you can receive an event telling you that the alert view was dismissed. It’s so common to give a UIAlertView a delegate that its designated initializer allows you to supply one; typically, the delegate will be the instance that summoned the alert view in the first place:

- (void) gameWon {
    UIAlertView* av =
        [[UIAlertView alloc] initWithTitle:@"Congratulations!"
                                   message:@"You won the game. Another game?"
                                  delegate:self
                         cancelButtonTitle:@"No, thanks."
                         otherButtonTitles:@"Sure!", nil];
    [av show];
}

- (void) alertView:(UIAlertView*) av
        didDismissWithButtonIndex: (NSInteger) ix {
    if (ix == 1) { // user said "Sure!"
        [self newGame];
    }
}

The delegation mechanism is the last piece of the puzzle needed to explain the built-in bootstrapping procedure of a minimal app like our Empty Window project. Recall, from Chapter 6, that the fourth argument to UIApplicationMain is the string name of the class of the shared application instance’s delegate. So, having instantiated the class of the shared application (usually UIApplication), UIApplicationMain instantiates the class nominated in its fourth argument — in this case, AppDelegate; there is now, therefore, before much of anything has happened, an AppDelegate instance. Moreover, UIApplicationMain sets the shared application’s delegate property to this AppDelegate instance. UIApplication’s delegate is typed as id <UIApplicationDelegate> — and, by golly, AppDelegate is declared as conforming to the UIApplicationDelegate protocol.

This, as we saw in Chapter 10, causes the shared application instance to bombard this AppDelegate instance with respondsToSelector: messages, to find out exactly which UIApplicationDelegate methods AppDelegate actually implements. One such method that it does implement is application:didFinishLaunchingWithOptions:. So the UIApplication instance now actually sends application:didFinishLaunchingWithOptions: to its delegate, the AppDelegate instance. That is why, in some earlier examples, we put code into the implementation of that method: this is code that is guaranteed, thanks to the UIApplication’s contract with its delegate, to run very early in the app’s lifetime. We know the application:didFinishLaunchingWithOptions: message will be sent, we know when it will be sent (early in our app’s lifetime), and we know to whom it will be sent (the application’s delegate object); so we’ve put appropriate code there, waiting to be called. Moreover, there is already boilerplate code in the project template’s implementation of this method that does some very important things, such as making our app’s window and showing it:

self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];

Note

The UIApplication delegate methods are also provided as notifications. This lets an instance other than the app delegate hear conveniently about application lifetime events, by registering for them. A few other classes provide duplicate events similarly; for example, UITableView’s delegate method tableView:didSelectRowAtIndexPath: is matched by a notification UITableViewSelectionDidChangeNotification.

By convention, many Cocoa delegate method names contain the modal verbs should, will, or did. A will message is sent to the delegate just before something happens; a did message is sent to the delegate just after something happens. A should method is special: it returns a BOOL, and you are expected to respond with YES to permit something or NO to prevent it. The documentation tells you what the default response is; you don’t have to implement a should method if the default response is always acceptable.

In many cases, a property will control the overall behavior; the delegate message lets you pick and choose the behavior based on circumstances at runtime. For example, whether the user can tap the status bar to make a scroll view scroll quickly to the top is governed by the scroll view’s scrollsToTop property; but even if this property’s value is YES, you can prevent this behavior for a particular tap by returning NO from the delegate’s scrollViewShouldScrollToTop:.

When you’re searching the documentation for how you can be notified of a certain event, be sure to consult the corresponding delegate protocol, if there is one. (And don’t forget to consult the class’s superclasses to see if one of them has a corresponding delegate protocol.) You’d like to know when the user taps in a UITextField to start editing it? You won’t find anything relevant in the UITextField class documentation; what you’re after is textFieldDidBeginEditing: in the UITextFieldDelegate protocol. You want to respond when the user rearranges items on your tab bar? Look in UITabBarControllerDelegate. You want to know how to make a UITextView zoomable (through the user making a pinch gesture)? A UITextView is a UIScrollView; a scroll view is not zoomable unless its delegate returns a view from viewForZoomingInScrollView:, documented under UIScrollViewDelegate.

Data Sources

A data source is like a delegate, except that its methods supply the data for another object to display. The chief Cocoa classes with data sources are UITableView, UICollectionView, UIPickerView, and UIPageViewController. In each case, the data source must formally conform to a protocol with required methods.

It comes as a surprise to some beginners that a data source is necessary at all. Why isn’t a table’s data just part of the table? Or why isn’t there at least some fixed data structure that contains the data? The reason is that such policies would violate generality. Use of a data source separates the object that displays the data from the object that manages the data, and leaves the latter free to store and obtain that data however it likes (see on model–view–controller in Chapter 13). The only requirement is that the data source must be able to supply information quickly, because it will be asked for it in real time when the data needs displaying.

Another surprise is that the data source is different from the delegate. But this again is only for generality; it’s an option, not a requirement. There is no reason why the data source and the delegate should not be the same object, and most of the time they probably will be.

In this simple example, we implement a UIPickerView that allows the user to select by name a day of the week (the Gregorian week, using English day names). The first two methods are UIPickerView data source methods; the third method is a UIPickerView delegate method:

- (NSInteger) numberOfComponentsInPickerView: (UIPickerView*) pickerView {
    return 1;
}

- (NSInteger) pickerView: (UIPickerView*) pickerView
        numberOfRowsInComponent: (NSInteger) component {
    return 7;
}

- (NSString*) pickerView:(UIPickerView*)pickerView
             titleForRow:(NSInteger)row
            forComponent:(NSInteger)component {
    NSArray* arr = @[@"Sunday",
                    @"Monday",
                    @"Tuesday",
                    @"Wednesday",
                    @"Thursday",
                    @"Friday",
                    @"Saturday"];
    return arr[row];
}

Actions

Recall the discussion of actions in Chapter 7. An action is a message emitted by an instance of a UIControl subclass (a control) reporting a significant user event taking place in that control. The UIControl subclasses (Chapter 25) are all simple interface objects that the user can interact with directly, like a button (UIButton), a switch (UISwitch), a segmented control (UISegmentedControl), a slider (UISlider), or a text field (UITextField).

The significant user events (control events) are listed under UIControlEvents in the Constants section of the UIControl class documentation. See Chapter 25 for a list of which controls implement which control events.

The way you hear about a control event is through an action message. A control maintains an internal dispatch table: for each control event, there is some number of target–action pairs, of which the action is a selector (the name of a method) and the target is the object to which that message is to be sent. When a control event occurs, the control consults its dispatch table, finds all the target–action pairs associated with that control event, and sends each action message to the corresponding target. This architecture is reminiscent of a notification (Figure 11.1).

figs/pios_1101.png

Figure 11.1. The target–action architecture


There are two ways to manipulate a control’s action dispatch table: you can configure an action connection in a nib (as explained in Chapter 7), or you can use code. To use code, you send the control the message addTarget:action:forControlEvents:, where the target: is an object, the action: is a selector, and the controlEvents: are designated by a bitmask (see Chapter 1 if you’ve forgotten how to construct a bitmask). Unlike a notification center, a control also has methods for introspecting the dispatch table (Chapter 25).

Recall the example from Chapter 7 (where b is a reference to a UIButton):

[b addTarget:self action:@selector(buttonPressed:)
        forControlEvents:UIControlEventTouchUpInside];

After that, whenever the user taps in the button, our buttonPressed: method will be called. It might, again as in Chapter 7, look like this:

- (void) buttonPressed: (id) sender {
    UIAlertView* av = [[UIAlertView alloc] initWithTitle:@"Howdy!"
                                                 message:@"You tapped me."
                                                delegate:nil
                                       cancelButtonTitle:@"Cool"
                                       otherButtonTitles:nil];
    [av show];
}

The signature for the action selector can be in any of three forms. The fullest form takes two parameters:

  • The control, usually typed as id.
  • The UIEvent that generated the control event.

A shorter form (the most commonly used form) omits the second parameter; a still shorter form omits both parameters.

Mac OS X Programmer Alert

If you’re an experienced Mac OS X Cocoa developer, you’ll note that there are some major differences between the Mac OS X implementation of actions and the iOS implementation. In Mac OS X, a control has just one action; in iOS, a control may respond to multiple control events. In Mac OS X, an action has just one target; in iOS, a single event can trigger multiple action messages to multiple targets. In Mac OS X, an action message selector comes in just one form; in iOS, there are three possible forms.

What is the UIEvent, and what is it for? Well, a touch event is generated whenever the user does something with a finger (sets it down on the screen, moves it, raises it from the screen). UIEvents are the lowest-level objects charged with communication of touch events to your app. A UIEvent is basically a timestamp (a double) along with a collection (NSSet) of touch events (UITouch). The action mechanism deliberately shields you from the complexities of touch events, but by electing to receive the UIEvent, you can still deal with those complexities if you want to. (See Chapter 18 for full details.)

Curiously, none of the action selector parameters provide any way to learn which control event triggered the current action selector call! Thus, for example, to distinguish a Touch Up Inside control event from a Touch Up Outside control event, their corresponding target–action pairs must specify two different action handlers; if you dispatch them to the same action handler, that handler cannot discover which control event occurred.

The Responder Chain

A responder is an object that knows how to receive UIEvents directly (see the previous section). It knows this because it is an instance of UIResponder or a UIResponder subclass. If you examine the Cocoa class hierarchy, you’ll find that just about any class that has anything to do with display on the screen is a responder. A UIView is a responder. A UIWindow is a responder. A UIViewController is a responder. Even a UIApplication is a responder. In iOS 5 and later, the app delegate is a responder.

If you look in the documentation for the UIResponder class, you’ll find that it implements four low-level methods for receiving touch-related UIEvents: touchesBegan:withEvent:, touchesMoved:withEvent:, touchesEnded:withEvent: and touchesCancelled:withEvent:. These are called to notify a responder of a touch event. No matter how your code ultimately hears about a user-related touch event — indeed, even if your code never hears about a touch event (because Cocoa reacted in some automatic way to the touch, without your code’s intervention) — the touch was initially communicated to a responder through one of these methods.

The mechanism for this communication starts by deciding which responder the user touched. The UIView methods hitTest:withEvent: and pointInside:withEvent: are called until the correct view (the hit-test view) is located. Then UIApplication’s sendEvent: method is called, which calls UIWindow’s sendEvent:, which calls the correct method of the hit-test view (a responder). I’ll cover all this again in full detail in Chapter 18.

The responders in your app participate in a responder chain, which essentially links them up through the view hierarchy. A UIView can sit inside another UIView, its superview, and so on until we reach the app’s UIWindow (a UIView that has no superview). The responder chain, from bottom to top, looks like this:

  1. The UIView that we start with (here, the hit-test view).
  2. The UIViewController that controls that UIView, if there is one.
  3. The UIView’s superview, and then its UIViewController if there is one. Repeat this step, moving up the superview hierarchy one superview at a time, until we reach…
  4. The UIWindow.
  5. The UIApplication.
  6. The UIApplication’s delegate.

Deferring Responsibility

The responder chain can be used to let a responder defer responsibility for handling a touch event. If a responder receives a touch event and can’t handle it, the event can be passed up the responder chain to look for a responder that can handle it. This can happen in two main ways: (1) the responder doesn’t implement the relevant method; (2) the responder implements the relevant method to call super.

For example, a plain vanilla UIView has no native implementation of the touch event methods. Thus, by default, even if a UIView is the hit-test view, the touch event effectively falls through the UIView and travels up the responder chain, looking for someone to respond to it. If this UIView is an instance of your own subclass, you might implement the touch event methods in that subclass to catch touch events in the UIView itself; but if the UIView is controlled by a UIViewController, you have already subclassed UIViewController, and that subclass is probably where the interface behavior logic for this UIView is already situated, so you might well prefer to implement the touch event methods there instead. You are thus taking advantage of the responder chain to defer responsibility for handling touch events from the UIView to its UIViewController, in a natural and completely automatic way.

Again, I’ll come back to this in Chapter 18; don’t worry about it for now. I’m actually telling you about the responder chain chiefly in order to discuss nil-targeted actions, which is the subject of the next section.

Nil-Targeted Actions

A nil-targeted action is a target–action pair in which the target is nil. There is no designated target object, so the following rule is used: starting with the hit-test view (the view with which the user is interacting), Cocoa looks up the responder chain for an object that can respond to the action message.

Suppose, for example, we have a UIButton inside a UIView. And suppose we run this code early in the button’s lifetime, where b is the button:

[b addTarget:nil action:@selector(doButton:)
       forControlEvents:UIControlEventTouchUpInside];

That’s a nil-targeted action. So what happens when the user taps the button? First, Cocoa looks in the UIButton itself to see whether it responds to doButton:. If not, then it looks in the UIView that is its superview. And so on, up the responder chain. If a responder is found that handles doButton:, the action message is sent to that object; otherwise, the message goes unhandled.

Thus, suppose the UIView containing the UIButton is an instance of your own UIView subclass. Let’s call it MyView. If MyView implements doButton:, then when the user taps the button, it is MyView’s doButton: that will be called.

To create a nil-targeted action in a nib, you form a connection to the First Responder proxy object (in the dock). This is what the First Responder proxy object is for! The First Responder isn’t a real object with a known class, so before you can connect an action to it, you have to define the action message within the First Responder proxy object, like this:

  1. Select the First Responder proxy in the nib, and switch to the Attributes inspector.
  2. You’ll see a table (probably empty) of user-defined nil-targeted First Responder actions. Click the Plus button and give the new action a signature; it must take a single parameter (so that its name will end with a colon).
  3. Now you can Control-drag from a control, such as a UIButton, to the First Responder proxy to specify a nil-targeted action with the signature you specified.

Swamped by Events

Your code runs only because Cocoa sends an event and you had previously set up a method ready to receive it. Cocoa has the potential to send lots of events, telling you what the user has done, informing you of each stage in the lifetime of your app and its objects, asking for your input on how to proceed. To receive the events that you need to hear about, your code is peppered with methods that are entry points — methods that you have written with just the right name and in just the right class so that they can be called by Cocoa through events. In fact, it is easy to imagine that in many cases your code for a class will consist almost entirely of entry points.

That fact is one of your primary challenges as an iOS programmer. You know what you want to do, but you have to divide it up and allocate it according to when Cocoa is going to call into your code. Before you’ve written a single line of your own code, the skeleton structure of a class is likely to have been largely mapped out for you by the need to be prepared to receive the events that Cocoa is going to want to send you.

Suppose, for example, that your iPhone app contains a screen that effectively consists entirely of a table view. (This is in fact an extremely probable scenario.) You’re most like to have a corresponding UITableViewController subclass; UITableViewController is a built-in UIViewController subclass, plus you’ll probably use this same class as the table view’s data source and delegate. In this single class, then, you’re likely to want to implement at a minimum the following methods:

initWithCoder: or initWithNibName:bundle:
UIViewController lifetime method, where you perform custom instance initializations.
viewDidLoad:
UIViewController lifetime method, where you perform view-related initializations.
viewWillAppear:
UIViewController lifetime method, where you set up states that need to apply only while your view is onscreen. For example, if you’re going to register for a notification or set up a timer, this is a likely place to do it.
viewDidDisappear:
UIViewController lifetime method, where you reverse what you did in viewWillAppear:. For example, this would be a likely place to unregister for a notification or invalidate a repeating timer that you set up in viewWillAppear:.
supportedInterfaceOrientations
UIViewController query method, where you specify what device orientations are allowed for this view.
numberOfSectionsInTableView:
tableView:numberOfRowsInSection:
tableView:cellForRowAtIndexPath:
UITableView data source query methods, where you specify the contents of the table.
tableView:didSelectRowAtIndexPath:
UITableView delegate user action method, where you respond when the user taps a row of the table.
dealloc
NSObject lifetime method, where you perform end-of-life cleanup. (If you’re not using ARC, you will have memory management tasks to perform here.)

Suppose, further, that you did in fact use viewWillAppear: to register for a notification and to set up a timer. Then that notification has a selector (unless you used a block), and the timer has a selector; you must therefore also implement the methods described by those selectors.

We already have, then, about a dozen methods whose presence is effectively a matter of boilerplate. These are not your methods; you are never going to call them. They are Cocoa’s methods, which you have placed here so that each can be called at the appropriate moment in the life story of your app.

(Don’t try to learn any of those method names now! I’ll talk in detail about these matters in Chapter 19 and Chapter 21. At the moment I’m just showing you that a major portion of the structure of this class is likely to be dictated to you by the event-driven nature of a Cocoa app.)

The logic of a program laid out in this fashion is by no means easy to understand! I’m not criticizing Cocoa here — indeed, it’s hard to imagine how else an application framework could work — but, purely as an objective matter of fact, the result is that a Cocoa program, even your own program, even while you’re developing it, is hard to read, because it consists of numerous disconnected entry points, each with its own meaning, each called at its own set moment which is not in any way obvious from looking at the program. To understand what our hypothetical class does, you have to know already such things as when viewWillAppear: is called and how it is typically used; otherwise, you don’t even know where to look to find the program’s logic and behavior, let alone how to interpret what you see when you do look there. And this difficulty is greatly compounded when you try to read someone else’s code (this is one reason why, as I mentioned in Chapter 8, sample code is not all that helpful to a beginner).

Looking at the code of an iOS program — even your own code — your eyes can easily glaze over at the sight of all these methods called automatically by Cocoa under various circumstances. To be sure, experience will teach you about such things as the overridden UIViewController methods and the table view delegate and data source methods. On the other hand, no amount of experience will tell you that a certain method is called as a button’s action or through a notification. Comments really help, and I strongly advise you, as you develop any iOS app, to comment every method, quite heavily if need be, saying what that method does and under what circumstances you expect it to be called — especially if it is an entry point, where it is Cocoa itself that will do the calling.

Perhaps the most common kind of mistake in writing a Cocoa app is not that there’s a bug in your code itself, but that you’ve put the code in the wrong place. Your code isn’t running, or it’s running at the wrong time, or the pieces are running in the wrong order. I see questions about this sort of thing all the time on the various online user forums (these are all actual examples that appeared over the course of just two days):

  • “There’s a delay between the time when my view appears and when my button takes on its correct title.” That’s because you put the code that sets the button’s title in viewDidAppear:. That’s too late; your code needs to run earlier, perhaps in viewWillAppear:.
  • “My subviews are positioned in code and they’re turning out all wrong.” That’s because you put the code that positions your subviews in viewDidLoad. That’s too early; your code needs to run later, when your view’s dimensions have been determined.
  • “My view is rotating even though my view controller’s supportedInterfaceOrientations says not to.” That’s because you implemented supportedInterfaceOrientations in the wrong class; it needs to be implemented in the UINavigationController that contains your view controller.
  • “I set up an action connection for Value Changed on a text field, but my code isn’t being called when the user edits.” That’s because you connected the wrong action; a text field emits Editing Changed, not Value Changed.

Adding to your challenges is that fact that you can’t really know precisely when an entry point will be called. The documentation may give you a general sense, but in most cases it doesn’t guarantee anything about precisely when events will arrive and in what order. What you think is going to happen, and even what the documentation leads you to believe is going to happen, might not be quite what really does happen. Your own code can trigger unintended events. The documentation might not make it clear just when a notification will be sent. There could even be a bug in Cocoa such that events are called in a way that seems to contradict the documentation. And you have no access to the Cocoa source code, so you can’t work out the underlying details. Therefore I also recommend that as you develop your app, you instrument your code heavily with caveman debugging (NSLog; see Chapter 9). As you test your code, keep an eye on the console output and check whether the messages make sense. You may be surprised at what you discover.

For example, in one app that I was developing, I suddenly found that in a UIViewController subclass, viewDidLoad was being called twice as the app started up, which should be impossible. Fortunately, my code was heavily instrumented with NSLog calls, or I would never have discovered this problem. Adding even more NSLog calls, I found that viewDidLoad was being called while I was still in the middle of executing awakeFromNib, which should really be impossible. The reason turned out to be my own mistake: I was referring to my class’s view property during awakeFromNib, which was causing viewDidLoad to be called. The problem went away when I corrected my mistake.

Delayed Performance

Some of your code tells Cocoa what to do. But Cocoa is a black box, so what Cocoa actually will do, and precisely when it will do it, is out of your control. Your code was executed in response to some event; but your code in turn may trigger a new event or chain of events. Sometimes this causes bad things to happen: there might be a crash, or Cocoa might appear not to have done what you said to do. One of the chief causes of these difficulties is the chain of triggered events itself. Sometimes you just need to step outside that chain for a moment and wait for everything to settle down before proceeding.

The technique for doing this is called delayed performance. You tell Cocoa to do something not right this moment, but in a little while, when things have settled down. Your purpose might be a matter of simple timing, such as when you want to do something different depending whether the user taps twice in quick succession or only once; basically, when the user first taps, you respond using delayed performance, to give the user time to tap again if two taps are intended (Chapter 18). Or perhaps you need only a very short delay, possibly even as short as zero seconds, just to let Cocoa finish doing something, such as laying out interface. Technically, you’re allowing the current run loop to finish, completing and unwinding the entire current method call stack, before proceeding further with your own code.

You’re likely to be using delayed performance a lot more than you might expect. With experience, you’ll develop a kind of sixth sense for when delayed performance might be the solution to your difficulties. There are three chief implementations of delayed performance that I use in my own code:

performSelector:withObject:afterDelay:
I mentioned this NSObject method at the end of Chapter 10. It limits you as to the signature of the selector — it must take one parameter or none — so you might have to restructure your own code slightly.
dispatch_after
I mentioned this in Chapter 3. It takes a block, not a selector, which can result in more direct and readable code.
dispatch_async
Often, the delay you’re after doesn’t need to be more than zero. What you’re trying to do is postpone the next step until the consequences of the previous step have worked themselves out. So it suffices to wait until nothing is happening. You can do this with a call to dispatch_async onto the same queue where everything is happening now, namely the main queue (dispatch_get_main_queue, Chapter 38).

In all three cases, what you propose to do will be done later on; you’re deliberately breaking out of your own code’s line-by-line sequence of execution. So a delayed performance call will be the last call in its method (or block), and cannot return any value.

In this example from one of my own apps, the user has tapped a row of a table, and my code responds by creating and showing a new view controller:

- (void) tableView:(UITableView *)tableView
        didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    TracksViewController *t =
        [[TracksViewController alloc]
         initWithMediaItemCollection:(self.albums)[indexPath.row]];
    [self.navigationController pushViewController:t animated:YES];
}

Unfortunately, the innocent-looking call to my TracksViewController method initWithMediaItemCollection: can take a moment to complete, so the app comes to a stop with the table row highlighted — very briefly, but just long enough to startle the user. To cover this delay with a sense of activity, I’ve rigged my UITableViewCell subclass to show a spinning activity indicator when it’s selected:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    if (selected) {
        [self.activityIndicator startAnimating]; // appear and spin
    } else {
        [self.activityIndicator stopAnimating]; // disappear
    }
    [super setSelected:selected animated:animated];
}

However, the spinning activity indicator never appears and never spins. The reason is that the events are stumbling over one another here. UITableViewCell’s setSelected:animated: isn’t called until the UITableView delegate method tableView:didSelectRowAtIndexPath: has finished. But the delay we’re trying to paper over is during tableView:didSelectRowAtIndexPath:; the whole problem is that it doesn’t finish fast enough. Delayed performance to the rescue! I’ll rewrite tableView:didSelectRowAtIndexPath: so that it finishes immediately — thus triggering setSelected:animated: immediately and causing the activity indicator to appear and spin — and call initWithMediaItemCollection: later on, when the interface has ironed itself out:

- (void) tableView:(UITableView *)tableView
        didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // tiny delay to allow spinner to start spinning
    double delayInSeconds = 0.1;
    dispatch_time_t popTime =
        dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        TracksViewController *t =
            [[TracksViewController alloc]
             initWithMediaItemCollection:(self.albums)[indexPath.row]];
        [self.navigationController pushViewController:t animated:YES];
    });
}

Here’s an example that I came across on the Internet, involving a crash. The developer has a table view each of whose rows contains a text field. If the user deletes everything in one of those text fields, the table row containing it should be deleted. The code is an implementation of one of the text field’s delegate methods:

- (void)textFieldEditingDidEnd:(UITextField *)textField {
    NSIndexPath *indexPath = // Index path of the row in the table view
    if ([textField.text length] == 0) {
        // Delete the cell from the table view
        [self.tableView deleteRowsAtIndexPaths:@[indexPath]
            withRowAnimation:UITableViewRowAnimationAutomatic];
    }
}

This was crashing. My suggestion — which worked — was to call deleteRowsAtIndexPaths:withRowAnimation: using delayed performance. The reason is that, as things stand, we are trying to delete the row containing the text field while the text field is still busy reporting to its delegate that editing is ending. With delayed performance, we allow Cocoa’s call to this delegate method to finish, and then we delete the row.

There will be many more examples of delayed performance later in this book.

Application Lifetime Events

As I explained in Chapter 6, your app’s one and only application object (a UIApplication instance, or on rare occasions a UIApplication subclass instance) is created for you as the shared application object by UIApplicationMain, along with its delegate; in the Xcode project templates, this is an instance of the AppDelegate class. As I’ve discussed earlier in this chapter, the application immediately starts reporting lifetime events through method calls to its delegate; subsequently, your other instances can also register to receive these same events as notifications. I can’t think of a better place in this book to describe these events, so I’m going to do so here and now.

What application lifetime events you can receive depends on whether or not your app participates in multitasking. In the old days, before iOS 4, there was no multitasking. If the user pressed the Home button while running your app, your app was terminated. The next time the user launched your app by tapping its icon, your app launched from scratch. Even under iOS 4 and later, your app can opt out of multitasking and behave like a pre–iOS 4 app, if you set the “Application does not run in background” key (UIApplicationExitsOnSuspend) in your Info.plist. For some apps, such as certain games, this might be a reasonable thing to do.

The suite of basic application lifetime events received by the app delegate in a nonmultitasking app is pretty simple:

application:didFinishLaunchingWithOptions:
The app has started up. This, as we have already seen, is the earliest opportunity for your code to configure the interface by creating and showing the app’s window, and it’s fair to assume that every app you ever write will do exactly that. If you don’t show your app’s interface, the user won’t see anything! (In an app with a main storyboard, however, the storyboard loading mechanism creates the window for you.) Of course you can and will perform other early initializations here.

Note

Starting in iOS 6, there’s a new event, application:willFinishLaunchingWithOptions:, that arrives even earlier than application:didFinishLaunchingWithOptions:. Its purpose is to allow your app to participate in the new mechanism for saving and restoring state. Since view controllers are the primary basis of this mechanism, I’ll discuss it in Chapter 19.

applicationDidBecomeActive:
The app has started up; received after application:didFinishLaunchingWithOptions:. Also received after the end of the situation that caused the app delegate to receive applicationWillResignActive:.
applicationWillResignActive:
Something has blocked the app’s interface. The most common cause is that the screen has been locked. An alert dialog from outside your app, or an incoming phone call whose interface takes over the screen, could also cause this event. When this situation ends, the app delegate will receive applicationDidBecomeActive:.
applicationWillTerminate:
The app is about to quit. This is your last signal to preserve state (typically, by storing information with NSUserDefaults) and perform other final cleanup tasks.

If your app participates in multitasking, as it almost certainly will, applicationWillTerminate: is virtually a dead letter. The Home button doesn’t terminate your app; it backgrounds and suspends it. This means that your app is essentially freeze-dried in the background; its process still exists, but it isn’t actively running, and it isn’t getting any events — though notifications can be stored by the system for later delivery if your app comes to the front once again. Your app is terminated, not because the user switches away from it, but because the system has killed it while it was suspended (for example, because it needed to reclaim the memory your suspended app was using). Thus you’ll probably never get applicationWillTerminate:, because when your app is terminated by the system, it was already suspended and incapable of receiving events.

Note

Under highly specialized circumstances (discussed, for instance, in Chapter 27 and Chapter 35), your app can be backgrounded without being suspended. Nevertheless, throughout this section I’ll speak as if backgrounding and suspension are one and the same.

In the multitasking world, you have to worry about what will happen when the app is suspended and when it returns from being suspended (applicationDidEnterBackground: and applicationWillEnterForeground:, and their corresponding notifications), and the notion of the application becoming inactive or active also takes on increased importance (applicationWillResignActive: and applicationDidBecomeActive:, and their notifications). These notifications all take on a wide range of meaning — indeed, in my opinion, the information your app is given is unfortunately too coarse-grained — so they are best understood by examining some typical scenarios:

The app launches freshly

Your app delegate receives these messages (just as in the premultitasking world):

  • application:didFinishLaunchingWithOptions:
  • applicationDidBecomeActive:
The user clicks the Home button

If your app is frontmost, it is suspended, and your app delegate receives these messages:

  • applicationWillResignActive:
  • applicationDidEnterBackground:
The user summons your suspended app to the front

Your app delegate receives these messages:

  • applicationWillEnterForeground:
  • applicationDidBecomeActive:

Note

If the user summons your suspended app to the front indirectly, another delegate message may be sent between these two calls. For example, if the user asks another app to hand a file off to your app (Chapter 36), your app receives application:handleOpenURL: between applicationWillEnterForeground: and applicationDidBecomeActive:. If the user taps a local notification alert belonging to your app (Chapter 26), your app receives application:didReceiveLocalNotification: between applicationWillEnterForeground: and applicationDidBecomeActive:.

The user double-clicks the Home button

The user can now work in the app switcher. If your app is frontmost, your app delegate receives this message:

  • applicationWillResignActive:
The user, in the app switcher, taps on your app’s window

Your app delegate receives this message:

  • applicationDidBecomeActive:
The user, in the app switcher, chooses another app

If your app is frontmost, your app delegate receives this message:

  • applicationDidEnterBackground:
A local notification alert (Chapter 26) from another app appears

If your app is frontmost, your app delegate receives this message:

  • applicationWillResignActive:
From a local notification alert, the user launches the other app

Your app delegate receives these messages:

  • applicationDidBecomeActive:
  • applicationWillResignActive:
  • applicationDidEnterBackground:
The screen is locked

If your app is frontmost, your app delegate receives these messages:

  • applicationWillResignActive:
  • applicationDidEnterBackground:
The screen is unlocked

If your app is frontmost, your app delegate receives these messages:

  • applicationWillEnterForeground:
  • applicationDidBecomeActive:
The user holds the screen-lock button down

The device offers to shut itself down. If your app is frontmost, your app delegate receives this message:

  • applicationWillResignActive:
The user, as the device offers to shut itself down, cancels

If your app is frontmost, your app delegate receives this message:

  • applicationDidBecomeActive:
The user, as the device offers to shut itself down, accepts

If your app is frontmost, your app delegate receives these messages:

  • applicationDidEnterBackground:
  • applicationWillTerminate: (probably the only way a normal app will receive this message in a multitasking world)

You can see what I mean when I say that this repertory of events is rather coarse-grained. applicationWillResignActive:, for example, could mean that the user is summoning the app switcher, or that another application’s local notification alert has appeared in front of your app, or that the user is locking the screen, or that the user has single-clicked the Home button to leave your app altogether, or that a phone call has arrived while your app was frontmost. But you can’t distinguish which of these things is happening.

Of all the tasks with which you’ll concern yourself over your app’s lifetime, probably the most important is saving state. If the user has done or specified things that the app needs to preserve, it must do so before it is terminated. Since a multitasking app is probably never going to be notified by applicationWillTerminate:, you’ll need to find an appropriate earlier moment. Unless your app is killed by the system outright, before the user’s eyes, for committing some crime (such as hogging the main thread for too long at a stretch), you’ll surely receive applicationDidEnterBackground: before being terminated, and indeed this might well be the last event your app ever receives; so it is clearly the default signal that you should save state. (You are given a little time to do this before your app is actually suspended; Chapter 38 discusses what to do if you think a little time might not be enough.)

In iOS 6, as I’ve already mentioned, there’s a new mechanism for helping you save state. It’s quite possible that your app, if it adopts this new mechanism, won’t need to save state in applicationDidEnterBackground: after all. (See Chapter 19.) On the other hand, you still might want to respond to applicationDidEnterBackground: by saving information that doesn’t qualify as state. For instance, your app stands a better chance of not being terminated while suspended, the less memory resources it uses; you might therefore take applicationDidEnterBackground: as a signal to release whatever large memory resources you can, perhaps writing them out to disk and recovering them when your app receives applicationWillEnterForeground:. (In addition, while running in the foreground, your app will be sent the delegate message applicationDidReceiveMemoryWarning: to inform you of a low memory situation. I’ll return to this topic in Chapter 19 as well.)