Seeing how memory management works on the iPhone

Seeing how memory management works on the iPhone

One of the main responsibilities of all good little applications is to deal with low memory. So the first line of defense is (obviously) to understand how you as a programmer can help them avoid getting into that state.

In the iPhone OS, each program uses the virtual-memory mechanism found in all modern operating systems. But virtual memory is limited to the amount of physical memory available. This is because the iPhone OS doesn’t store "changeable" memory (such as object data) on the disk to free up space, and then read it in later when it’s needed. Instead, the iPhone OS tries to give the running application the memory it needs — using memory pages that contain read-only contents (such as code), where all it has to do is load the "originals" back into memory when they’re needed. Of course, this may be only a temporary fix if those resources are needed again a short time later.

If memory continues to be limited, the system may also send notifications to the running application, asking it to free up additional memory. This is one of the critical events that all applications must respond to.

Observing low-memory warnings

When the system dispatches a low-memory notification to your application, it is something you must pay attention to. If you don’t, it is a reliable recipe for disaster. (Think of your low-fuel light going on as you approach a sign that says "Next services 100 miles.") UIKit provides several ways of setting up your application so that you receive timely low-memory notifications:

✓ Implement the applicationDidReceiveMemoryWarning: method of your application delegate. Your application delegate could then release any data structure or objects it owns — or notify the objects to release memory they own.

✓ Override the didReceiveMemoryWarning: method in your custom UlViewController subclass. The view controller could then release views — or even other view controllers — that are off-screen.

✓ Register to receive the UIApplicationDidReceiveMemoryWarning Notification: notification. A model object could then release data structures or objects it owns that it doesn’t need immediately and can re-create later.

UIKit Your code

Each of these strategies gives a different part of your application a chance to free up the memory it no longer needs (or doesn’t need right now). As for how you actually get these strategies working for you, while I will mention a strategy for implementing the view controller’s didReceiveMemoryWarning: in Chapter 14, this is something that is dependent on your application’s architecture. That means you’ll need to explore it on your own.

Not freeing up enough memory will result in the iPhone’s OS sending your application the applicationWillTerminate: message and shutting you down. For many applications, though, the best defense is a good offense, and you need to manage your memory effectively and eliminate any memory leaks in your code.

Avoiding the warnings

When you create an object — a window or button for example — memory is allocated to hold that object’s data. The more objects you create, the more memory you use, and the less there is available for additional objects you might need. Obviously, it’s important to make available (deallocate) the memory that an object was using when the object is no longer needed. This is what is meant by memory management.

The Objective-C language — the application-programming language used to develop iPhone applications — uses reference counting to figure out when to release the memory allocated to an object. It’s your responsibility (as a programmer) to keep the memory-management system informed when an object is no longer needed.

Responding to interruptions

Responding to interruptionsVarious events besides termination can interrupt your application to allow the user to respond — for example, incoming phone calls, SMS messages, calendar alerts, or the user pressing the Sleep button on an iPhone. Such interruptions may only be temporary. If the user chooses to ignore an interruption, your application continues running as before. If the user decides to answer the phone or reply to an SMS message, however, your application will be terminated.

Figure 6-8 shows the sequence of events that occurs during the arrival of a phone call, SMS message, or calendar alert. Here’s what that looks like step by step:

1. The system detects an incoming phone call or SMS message, or a calendar event occurs.

2. The system sends your application delegate the applicationWill ResignActive: message.

Because these interruptions cause a temporary loss of control by your application — meaning that touch events are no longer sent to your applications — it is up to you to prevent what is known in the trade as a "negative user experience." For example, if your application is a game, you should pause the game.

3. The system displays an alert panel with information about the event.

The user can choose to ignore the event or respond to it.

4. If the user ignores the event, the system sends your application delegate the applicationDidBecomeActive: message and resumes the delivery of touch events to your application.

You can use this delegate method to restore the application to the state it was in before the interruption. What you do depends on your application. In some applications, it makes sense to resume normal processing. In others — if you’ve paused a game, for example — you could leave the game paused until the user decides to resume play.

5. If the user responds to the event, instead of ignoring it, the system sends your application delegate the applicationWillTerminate: Message.

Your application should do what it needs to do in order to terminate gracefully.

The way the Sleep/Wake button is handled is a little different. When the application enters or resumes from a sleep state, two messages are sent to the application delegate: applicationWillResignActive: and applica-tionDidBecomeActive:, respectively. In this case, your application always resumes, though the user might immediately launch a different application.

Other Runtime Considerations

Other Runtime ConsiderationsLaunch, initialize, process, terminate, launch, initialize, process, terminate. . . it has a nice rhythm to it, doesn’t it? And those are the four major stages of the application’s life cycle. But life isn’t simple — and neither is runtime. To mix things up a bit, your application will also have to come to terms with interruptions and memory management.

BE*

Termination

TerminationGetting stuff to (safely) shut down is another application delegate responsibility. To handle termination, the application delegate implements the delegate method applicationWillTerminate: to save any unsaved data or key application state (where the user is in the application — the current view and stuff like that) to disk. (Okay, I know, the disk in the iPhone is not really a disk; it’s a solid state drive that Apple calls a disk, but if it calls it that, I probably should, too, just so I don’t confuse too many people.). You can also use this method to perform additional cleanup operations, such as deleting temporary files.

Event Processing

Event ProcessingAfter a user launches your application, the functionality provided in the UIKit framework manages most of the application’s infrastructure. Part of the initialization process mentioned in the previous section involves setting up the main run loop and event handling code, which is the responsibility of

The UIApplication object.

When the application is on-screen, it’s driven by external events — say, stubby fingers touching sleek screens, as shown in Figure 6-7. Here’s a rundown of how external events drive an application:

1. You have an event — the user taps a button, for example.

The touch of a finger (or lifting it from the screen) adds a touch event to the application’s event queue, where it’s encapsulated in — placed into — a UIEvent object. There is a UITouch object for each finger touching the screen so you can track individual touches. As the user manipulates the screen with his or her fingers, the system reports the changes for each finger in the corresponding UITouch object.

My advice to you: Don’t let your eyes glaze over here. This UIEvent and UITouch stuff is important, as you’ll discover when I show you how to handle touch events while walking you through building the more advanced parts of the ReturnMeTo application.

2. The run loop monitor dispatches the event.

When there is something to process, the event-handling code of the UIApplication processes touch events by dispatching them to the appropriate responder object — the object that has signed up to take responsibility for doing something when an event happens (when the user touches the screen, for example). Responder objects can include

Instances of UIApplication, UlWindow, UlView, and its subclasses (all which inherit from UlResponder).

3. A responder object decides how to handle the event.

For example, a touch event occurring in a button (view) will be delivered to the button object. The button handles the event by sending an action message to another object — in this case, the UlViewController object. Setting it up this way enables you to use standard button objects without having to muck about in their innards — just tell the button what method you want invoked in your view controller, and you’re basically set.

Processing the message may result in changes to a view, or a new view altogether, or some other kind of change in the user interface. When this happens, the view and graphics infrastructure takes over and processes the required drawing events.

4. You’re sent back to the event loop.

After an event is handled or discarded, control passes back to the run loop. The run loop then processes the next event or puts the thread to sleep if there’s nothing more for it to do.

Operating system

Event queue

Application objects

Figure 6-7:

Processing events in the main run loop.

Initialization

InitializationThe next step is for the UIApplication to send the ReturnMeToApp Delegate applicationDidFinishLaunching: message. Step 5 in Figure 6-6 represents what happens when the applicationDidFinish Launching: method is invoked.

This figure looks exactly like Figure 6-4, except I added a Step 5: putting the view into the window and then making the window visible. At this point, you’d do any other application initialization as well — and return everything to what it was like when the user last used the application.

Fi П П UqkilMndaw. ii lb

Ш s | ш i л О

VrfwUfidf Ms 11bury infp-rrtar ® •

TIE tlripHid

Figure 6-6 is more than just a conceptual diagram, as you can see from Listing 6-1, which shows two instance variables, window, and viewController. These are automatically "filled in" for you when your application is launched. Then, in the applicationDidFinishLaunching: method, the view controller and its view are added to the window, and the window becomes visible. Note that this was generated automatically by Xcode. (I’ll get into what all those strange things like IBOutlet and @property mean in the next chapter.)

Figure 6-6:

The applic ation Did Finish Launch ing: method installs the view in the window and makes the window visible.

Listing 6-1: ReturnMeToAppDelegate

// ReturnMeToAppDelegate. h

#import <UIKit/UIKit. h>

@class ReturnMeToViewController;

@interface ReturnMeToAppDelegate : NSObject

<UIApplicationDelegate> {

UIWindow *window;

ReturnMeToViewController *viewController;

}

@property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet

@end

// ReturnMeToAppDelegate. m

#import "ReturnMeToAppDelegate. h" #import "ReturnMeToViewController. h"

@implementation ReturnMeToAppDelegate @synthesize window; @synthesize viewController;

- (void)applicationDidFinishLaunching:

(UIApplication *)application {

[window addSubview:viewController. view]; [window makeKeyAndVisible];

}

JjJJlBEH

What this does is quite a bit; what it doesn’t do is connect objects added to the user interface with the objects that need to know about them. How does my application access the phone number that the user enters, for example? Of course, I could root around in the code, but it would be much easier to have Interface Builder do it at application launch. I show you how that is (easily) done in the next chapter.

Your goal during startup should be to present your application’s user interface as quickly as possible — quick initialization = happy users. Don’t load large data structures that your application won’t use right away. If your application requires time to load data from the network (or perform other tasks that take noticeable time), get your interface up and running first — and then launch the slow task on a background thread. Then you can display a progress indicator or other feedback to the user to indicate that your application is loading the necessary data or doing something important.

The application delegate object is usually derived from NSObject, the root class (the very base class from which all iPhone application objects are derived), although it can be an instance of any class you like, as long as it adopts the UIApplicationDelegate protocol. The methods of

This protocol correspond to behaviors that are needed during the application life cycle and are your way of implementing this custom behavior. Although you are not required to implement all of the methods of the

UIApplicationDelegate protocol, every application should implement the following critical application tasks:

✓ Initialization, which I have just covered

✓ Responding to interruptions

✓ Responding to low memory warnings

I show you what has to be done to carry out these tasks in the last two sections.

It all starts with the main nib file

It all starts with the main nib file

When you create a new project using a template — quite the normal state of affairs, as I explain in Chapter 3 — the basic application environment is included. That means when you launch your application, an application object is created and connected to the window object, the run loop is established, and so on — despite the fact that you haven’t done a lick of coding. Most of this work is done by the UIApplicationMain function as illustrated back in Figure 6-1.

But what does the UIApplicationMain function actually do? I’m glad you asked. When it goes through its paces, the process works more or less as follows, as illustrated in Figure 6-2.

1. An instance of UlApplication is created.

2. UlApplication looks in the info. plist file, trying to find the main nib file.

It makes its way down the Key column until it finds the Main Nib File Base Name entry. Eureka! It peeks over at the Value column and sees that the value for the Main Nib File Base Name entry is MainWindow. nib.

3. UlApplication loads MainWindow. xib.

The file MainWindow. xib is what causes your application’s delegate, main window, and view controller instances to get created at runtime. Remember, this file is provided as part of the project template. You don’t need to change or do anything here. This is just a chance to see what’s going on behind the scenes.

UlApplication

<UIApplicationMain>

Figure 6-2:

The application is launched.

To take advantage of this once-in-a-lifetime opportunity, go back to your project window in Xcode, expand the Resources folder in the Groups & Files listing on the left and then double-click MainWindow. xib. (You do have a project, right? If not, check out Chapter 4.) When Interface Builder opens, take a look at the nib file’s main window — the one labeled MainWindow. xib, which should look like the MainWindow. xib you see in Figure 6-2. Double-click the ReturnMeToViewController object as well as the Window object, if they are not already open. You should end up with three windows open, as shown in Figure 6-3.

Figure 6-3 shows MainWindow. xib contains five files. The objects you see are as follows:

 A File’s Owner proxy object: The File’s Owner object is actually the UIApplication instance. This object isn’t created when the file

Is loaded as are the window and views. It’s already created by the UIApplicationMain object before the nib file is loaded.

 First Responder proxy object: This object is the first entry in an application’s responder chain, which is constantly updated while the application is running to (usually) point to the object with which the user is currently interacting. If, for example, the user were to tap a text field to enter some data, the first responder would become the text field object.

 An instance of ReturnMeToAppDelegate set to be the application’s delegate.

 An instance of the ReturnMeToViewController.

 A window: The window has its background set to white and is set to be visible at launch. This is the window you’ll see when the application launches.

Okay, so all these disparate parts of the MainWindow. xib are loaded by UIApplication. What happens next is shown in Figure 6-4. The numbers in the figure correspond to the following steps:

1. Create ReturnMeToAppDelegate.

2. Create Window.

3. Create ReturnMeToViewController.

4. ReturnMeToViewController:LoadView loads the view from the ReturnMeToViewController. xib file.

Wait a sec — how does the ReturnMeToViewController know that it’s supposed to do that? If you double-click the

ReturnMeToViewController object in the MainWindow. xib window (refer back to Figure 6-3), you can see the ReturnMeToViewController window with its view. There, right in the middle of that view, it tells you that it will be "Loaded from ReturnMeToViewController. nib." (As I said in Chapter 4, a nib file type used to be the term of choice. Here is a vestige of that. Don’t worry; despite the nib business, it really will be the. xib file.) If you use the Inspector to look at the View Controller attributes (see Figure 6-5), you can see the NIB Name drop-down menu specifies said NIB name — the nib file for the view controller. In this case, you see ReturnMeToViewController specified. This makes the connection explicit between the MainWindow. xib and the ReturnMeToViewController. xib. All done without any fuss or bother, I might add, by Xcode when you created the project from the template.

Figure 6-3:

The application’s Main Window. xib as it appears in Interface Builder.

П П UqkilMndow. il lb

111 ■ I ш i л О

Figure 6-4:

Creating the App Delegate, window, view controller, and the view.

Figure 6-5:

Connecting the Main Window. xib and the ReturnMe ToView Controller xib.

Application Anatomy 101 — The Life Cycle

Application Anatomy 101 — The Life Cycle

The short-but-happy life of an application begins when a user launches it by tapping its icon on the Home screen. The system launches your application by calling its main function.

The main function does only three things:

✓ Sets up an autorelease pool.

✓ Calls the UIApplicationMain function.

✓ At termination, releases the autorelease pool.

To be honest, this whole main function thing is not something you even need to think about. What is important is what happens after the UIApplicationMain function is called. The whole ball of wax is shown in Figure 6-1. Here’s the play-by-play:

1. The main nib file is loaded.

A nib file is a resource file that contains the specifications for one or more objects. The main nib file usually contains a window object of some kind, the application delegate object, and any other key objects. When the file is loaded, the objects are reconstituted (think "instant application") in memory.

For our ReturnMeTo example, this is the moment of truth when the

ReturnMeToAppDelegate, ReturnMeToViewController, its view, and the main window are created.

UIKit Your code

For more on those objects and the roles they play in applications, see Chapter 2.

2. The UIApplicationMain sends the application delegate the

ApplicationDidFinishLaunching: message.

This step is where you initialize and set up your application. You may display your main application window as if the user was starting from scratch, or the way the window looked when the user last exited the application. The application delegate object is a custom object that you code. It is responsible for some of the application-level behavior of your application. (Delegation is an extensively used design pattern that I explain in Chapter 2.)

3. The UIKit framework sets up the event loop.

The event loop is the code responsible for polling input sources — the screen, for example. Events, such as touches on the screen, are sent to the object — say, a controller — that you have specified to handle that kind of event. These handling objects contain the code that implements what you want your application to do in response to that particular event. A touch in a control may result in a change in what the user sees in a view, a switch to a new view, or even the playing of "My Melancholy Baby."

4. When the user performs an action that would cause your application to quit, UIKit notifies your application and begins the termination process.

Your application delegate is sent the applicationWillTerminate: message, and you do what you need to do to terminate your application, including saving where the user was in the application. Saving is important, because then, when the application is launched again (see Step 2 above) and the UIApplicationMain sends the application delegate the applicationDidFinishLaunching, message you can restore the application to where the user left off.

A Lot Accomplished Very Quickly

A Lot Accomplished Very QuicklyIn only a few pages, you’ve accomplished quite a bit. I want to emphasize, as you will see, that what I have done is not just a design. What you see here is the specification for "code" that will take what I have laid out in Interface Builder and create the objects that will implement it at runtime.

I do have to write code, however, if I want the application to actually do something. But before I get into that subject in detail, it is important that you understand how the application works at runtime — how the objects fit together and communicate. I explain what you need to know about that whole business in the next chapter.

Adding an Application Icon

Adding an Application IconOne of the design goals for the ReturnMeTo application was to make it obvious to someone who found my iPhone that he or she should touch the application icon.

But if you click on the Simulator’s home button — the black button with the white square at the very bottom of the window — what you see in Figure 5-17 is an application icon that is noticeable only for what it is not. What I need is an icon that reaches out and says, "touch me!"

An application icon is simply a 57-by-57-pixel. png file, just like the one I used for our image (albeit smaller) in the "Adding Graphics and the Rest of the Elements" section, earlier in the chapter. I created an icon matching those measurements in a graphics program and added it to the ReturnMeTo project in the same way I added the image file earlier — by dragging it into the Resources folder.

After I add the icon, I also need to specify that this icon is what I want used as the application’s icon. I do that using one of those other mysterious files you see in the Resources folder. Here’s how:

1. In the Resources folder, click the info. plist file, as shown in Figure 5-18.

The contents of the info. plist file are displayed in the Editor pane. You’re treated to some information about the application, including an item in the Key column labeled Icon file.

Figure 5-18:

Adding the icon in the info. plist.

2. Double-click in the empty space in the Value column next to Icon file.

3. Type in ReturnMeTo icon. png (or whatever name you chose to give your image) and then build the project as you normally would.

You know, clicking the Build and Run button in the Project Window toolbar, choosing BuildOBuild and Go (Run) from the main menu or pressing ^+Return.

I’ll be doing more with the info. plist and its various settings when I get ReturnMeTo ready for the App store in Chapter 12.

Click the Home button, and you should be able to see your application icon. (For a peek at mine, check out Figure 5-19.)

Figure 5-19:

The

ReturnMeTo icon on the iPhone.