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

440CHAPTER 12: Application Settings and User Defaults

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

self.warpFactorSlider = nil;

}

We added a call to our refreshFields method, whose three lines of code get a reference to the standard user defaults, and then use the outlets for the switch and slider to make them display the values stored in the user defaults.

- (void)refreshFields {

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; engineSwitch.on = [defaults boolForKey:kWarpDriveKey]; warpFactorSlider.value = [defaults floatForKey:kWarpFactorKey];

}

We also implemented the engineSwitchTapped and warpSliderTouched action methods, so that we could stuff the values from our controls back into the user defaults when the user changes them.

Keeping It Real

Now you should be able to run your app, view the settings, and then press the home button and open the Settings app to tweak some values. Hit the home button again, launch your app again, and you may be in for a surprise. If you’re running iOS 4.0 or later on your iOS device or simulator (and we bet you are), then when you go back to your app, you won’t see the settings change! They’ll remain as they are, showing the old values.

When you’re using iOS 4, hitting the home button while an app is running doesn’t actually quit the app. Instead, the operating system suspends the app in the background, leaving it ready to be quickly fired up again. This is great for switching back and forth between applications, since the amount of time it takes to reawaken a suspended app is much shorter than what it takes to launch it from scratch. However, in our case, we need to do a little more work so that when our app wakes up, it effectively gets a slap in the face, reloads the user preferences, and redisplays the values they contain.

You’ll learn more about background applications in Chapter 15, but we’ll give you a sneak peek at the basics of how to make your app notice that it has been brought back to life. To do this, we’re going to sign up each of our controller classes to receive a notification that is sent by the application when it wakes up from its state of suspended execution.

A notification is a lightweight mechanism that objects can use to communicate with each other. Any object can define one or more notifications that it will publish to the application’s notification center, which is a singleton object that exists only to pass these notifications between objects. Notifications are usually indications that some event occurred, and objects that publish notifications include a list of notifications in their documentation. The UIApplication class publishes a number of notifications (you can find them in the Xcode documentation viewer, toward the bottom of the UIApplication

www.it-ebooks.info

CHAPTER 12: Application Settings and User Defaults

441

page). The purpose of most notifications is usually pretty obvious from their names, but the documentation contains further information if you find one whose purpose is unclear.

Our application needs to refresh its display when the application is about to come to the foreground, so we are interested in the notification called

UIApplicationWillEnterForegroundNotification. When we write our viewDidLoad method, we will subscribe to that notification and tell the notification center to call this method when that notification happens. Add this method to both

BIDMainViewController.m and BIDFlipsideViewController.m:

- (void)applicationWillEnterForeground:(NSNotification *)notification { NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults synchronize];

[self refreshFields];

}

The method itself is quite simple. First, it gets a reference to the standard user defaults object, and calls its synchronize method, which forces the User Defaults system to save any unsaved changes and also reload any unmodified preferences from storage. In effect, we’re forcing it to reread the stored preferences so that we can pick up the changes that were made in the Settings app. Then it calls the refreshFields method, which each class uses to update its display.

Now, we need to make each of our controllers subscribe to the notification we’re interested in by adding the following lines to the bottom of the viewDidLoad method in both BIDMainViewController.m and BIDFlipsideViewController.m. Here’s the version for BIDMainViewController.m:

- (void)viewDidLoad { [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

UIApplication *app = [UIApplication sharedApplication]; [[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(applicationWillEnterForeground:)

name:UIApplicationWillEnterForegroundNotification

object:app];

}

And here’s the version for BIDFlipsideViewController.m:

- (void)viewDidLoad { [super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

[self refreshFields];

UIApplication *app = [UIApplication sharedApplication]; [[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(applicationWillEnterForeground:)

name:UIApplicationWillEnterForegroundNotification

object:app];

}

www.it-ebooks.info

442

CHAPTER 12: Application Settings and User Defaults

We start off by getting a reference to our application instance and use that to subscribe to the UIApplicationWillEnterForegroundNotification, using the default

NSNotificationCenter instance and a method called addObserver:selector:name:object:. We then pass the following to this method:

For an observer, we pass self, which means that our controller class (each of them individually, since this code is going into both of them) is the object that needs to be notified.

For selector, we pass a selector to the applicationWillEnterForeground: method we just wrote, telling the notification center to call that method when the notification is posted.

The third parameter, name:, is the name of the notification that we’re interested in receiving.

The final parameter, object:, is the object from which we’re interested in getting the notification. If we passed nil for the final parameter, we would get notified any time any method posted the

UIApplicationWillEnterForegroundNotification.

That takes care of updating the display, but we also need to consider what happens to the values that are put into the user defaults when the user manipulates the controls in our app. We need to make sure that they are saved to storage before control passes to another app. The easiest way to do that is to call synchronize as soon as the settings are changed, by adding one line to each of our new action methods in

BIDFlipsideViewController.m:

- (IBAction)engineSwitchTapped {

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setBool:engineSwitch.on forKey:kWarpDriveKey];

[defaults synchronize];

}

- (IBAction)warpSliderTouched {

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; [defaults setFloat:warpFactorSlider.value forKey:kWarpFactorKey];

[defaults synchronize];

}

NOTE: Calling the synchronize method is a potentially expensive operation, since the entire contents of the user defaults in memory must be compared with what’s in storage. When you’re dealing with a whole lot of user defaults at once and want to make sure everything is in sync, it’s best to try to minimize calls to synchronize so that this whole comparison isn’t performed over and over again. However, calling it once in response to each user action, as we’re doing here, won’t cause any noticeable performance problems.

There’s one more thing to take care of in order to make this work as cleanly as possible. You already know that you must clean up your memory by setting properties to nil when

www.it-ebooks.info

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