Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Beginning iOS5 Development.pdf
Скачиваний:
7
Добавлен:
09.05.2015
Размер:
15.6 Mб
Скачать

552

CHAPTER 15: Grand Central Dispatch, Background Processing, and You

applicationDidBecomeActive as well. And remember that applicationDidBecomeActive will be called not only when we switch from Inactive back to Active, but also when the app launches and becomes Active in the first place! That means we’re starting our animations twice, and Core Animation doesn’t seem to deal well with multiple animations trying to change the same attributes at the same time. The solution is simply to delete the line you previously added at the end of viewDidLoad:

[self rotateLabelDown];

Now build and run the app again, and you should see that it’s animating properly. Once again, send an SMS message to your iPhone. This time when the system alert appears, you’ll see that the animation in the background stops as soon as the text is right-side up. Tap the Close button, and the animation starts back up.

Now you’ve seen what to do for the simple case of switching from Active to Inactive and back. The bigger task, and perhaps the more important one, is dealing with a switch to the background and then back to foreground.

Handling the Background State

As we mentioned earlier, switching to the Background state is pretty important to ensure the best possible user experience. This is the spot where you’ll want to discard any resources that can easily be reacquired (or will be lost anyway when your app goes silent) and save information about your app’s current state, all without occupying the main thread for more than five seconds.

To demonstrate some of these behaviors, we’re going to extend State Lab in a few ways. First, we’re going to add an image to the display so that we can later show you how to get rid of the in-memory image. Then we’re going to show you how to save some information about the app’s state so we can easily restore it later. Finally, we’ll show you how to make sure these activities aren’t taking up too much main thread time, by putting all this work into a background queue.

Removing Resources When Entering the Background

Start by adding smiley.png from the book’s source archive to your project’s State Lab folder. Be sure to enable the checkbox that tells Xcode to copy the file to your project directory.

Now, let’s add properties for both an image and an image view to BIDViewController.h:

@interface BIDViewController : UIViewController

@property (strong, nonatomic) UILabel *label;

@property (strong, nonatomic) UIImage *smiley; @property (strong, nonatomic) UIImageView *smileyView;

@end

Then switch to the .m file again, and add the usual memory-management code:

@implementation BIDViewController

www.it-ebooks.info

CHAPTER 15: Grand Central Dispatch, Background Processing, and You

553

@synthesize label; @synthesize animate;

@synthesize smiley, smileyView;

.

.

.

-(void)viewDidUnload {

//Release any retained subviews of the main view.

//e.g. self.myOutlet = nil;

self.label = nil; self.smiley = nil; self.smileyView = nil;

[super viewDidUnload];

}

Now, let’s set up the image view and put it on the screen by modifying the viewDidLoad method as shown here:

- (void)viewDidLoad { [super viewDidLoad];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive)

name:UIApplicationWillResignActiveNotification object:[UIApplication sharedApplication]];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive)

name:UIApplicationDidBecomeActiveNotification object:[UIApplication sharedApplication]];

CGRect bounds = self.view.bounds;

CGRect labelFrame = CGRectMake(bounds.origin.x, CGRectGetMidY(bounds) - 50, bounds.size.width, 100);

self.label = [[UILabel alloc] initWithFrame:labelFrame]; label.font = [UIFont fontWithName:@"Helvetica" size:70]; label.text = @"Bazinga!";

label.textAlignment = UITextAlignmentCenter; label.backgroundColor = [UIColor clearColor];

// smiley.png is 84 x 84

CGRect smileyFrame = CGRectMake(CGRectGetMidX(bounds) - 42, CGRectGetMidY(bounds)/2 - 42, 84, 84);

self.smileyView = [[UIImageView alloc] initWithFrame:smileyFrame]; self.smileyView.contentMode = UIViewContentModeCenter;

NSString *smileyPath = [[NSBundle mainBundle] pathForResource:@"smiley" ofType:@"png"];

self.smiley = [UIImage imageWithContentsOfFile:smileyPath]; self.smileyView.image = self.smiley;

[self.view addSubview:smileyView];

[self.view addSubview:label];

}

Build and run the app, and you’ll see the incredibly happy-looking smiley face toward the top of your screen (see Figure 15–5).

www.it-ebooks.info

554

CHAPTER 15: Grand Central Dispatch, Background Processing, and You

Figure 15–5. The State Lab application doing its label-rotating magic with the addition of a smiley icon

Next, press the home button to switch your app to the background, and then tap its icon to launch it again. You’ll see that the app starts up right where it left off. That’s good for the user, but we’re not optimizing system resources as well as we could.

Remember that the fewer resources we use while our app is Suspended, the lower the risk that iOS will terminate our app entirely. By clearing any easily re-created resources from memory when we can, we increase the chance that our app will stick around and therefore relaunch super-quickly.

Let’s see what we can do about that smiley face. We would really like to free up that image when going to the Background state and re-create it when coming back from the Background state. To do that, we’ll need to add two more notification registrations toward the top of viewDidLoad, just after [super viewDidLoad]:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground)

name:UIApplicationDidEnterBackgroundNotification object:[UIApplication sharedApplication]];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground)

name:UIApplicationWillEnterForegroundNotification object:[UIApplication sharedApplication]];

And we want to implement the two new methods:

- (void)applicationDidEnterBackground { NSLog(@"VC: %@", NSStringFromSelector(_cmd)); self.smiley = nil;

self.smileyView.image = nil;

}

- (void)applicationWillEnterForeground { NSLog(@"VC: %@", NSStringFromSelector(_cmd));

NSString *smileyPath = [[NSBundle mainBundle] pathForResource:@"smiley" ofType:@"png"];

www.it-ebooks.info

CHAPTER 15: Grand Central Dispatch, Background Processing, and You

555

self.smiley = [UIImage imageWithContentsOfFile:smileyPath]; self.smileyView.image = self.smiley;

}

Build and run the app, and repeat the same steps of backgrounding your app and switching back to it. You should see that from the user’s standpoint, the behavior appears to be about the same. If you want to verify for yourself that this is really happening, comment out the contents of the applicationWillEnterForeground method, and build and run the app again. You’ll see that the image really does disappear.

Saving State When Entering the Background

Now that you’ve seen an example of how to free up some resources when entering the Background state, it’s time to think about saving state. Remember that the idea is to save all information relevant to what the user is doing, so that in case your application is later dumped from memory, the next time users return, they can still pick up right where they left off.

The kind of state we’re talking about here is really application-specific. You might want to keep track of which document users were looking at, their cursor location in a text field, which application view was open, and so on. In our case, we’re just going to keep track of the selection in a segmented control.

Start by adding a new instance variable and property in BIDViewController.h:

@interface BIDViewController : UIViewController

@property (strong, nonatomic) UILabel *label; @property (strong, nonatomic) UIImage *smiley; @property (strong, nonatomic) UIImageView *smileyView;

@property (strong, nonatomic) UISegmentedControl *segmentedControl;

@end

Then implement the usual boilerplate code for accessors and memory management in

BIDViewController.m:

.

.

.

@implementation BIDViewController

@synthesize label;

@synthesize smiley, smileyView;

@synthesize segmentedControl;

.

.

.

- (void)viewDidUnload { [super viewDidUnload];

//Release any retained subviews of the main view.

//e.g. self.myOutlet = nil;

self.label = nil; self.smiley = nil; self.smileyView = nil;

www.it-ebooks.info

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]