问题
I have a three tab application that shares a plist for connection information (Client ID, Server Address, Port Number). In each of the view controllers, an NSUserDefaults object is initialized within the viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
// load default settings into class instance variables
defaults = [NSUserDefaults standardUserDefaults];
self.clientID = [defaults objectForKey:@"clientID"];
self.serverAddress = [defaults objectForKey:@"serverAddress"];
self.serverPort = [defaults objectForKey:@"serverPort"];
}
One of my views represents a "Settings" page that allows a user to make changes to the plist. However, when the plist is updated, the changes aren't reflected across all of the tab views because a synchronize is needed for each of the objects:
[defaults synchronize];
I've learned that the viewDidLoad method is only called once during the lifetime of an application (at least for a Tab Bar application), so, I can't put the synchronize calls here. I then turned to the AppDelegate class and discovered the tabBarController method. How do I use this method to synchronize the NSUserDefaults objects across all view controllers without the need for a sync button? Is this even the correct way of sharing/adjusting preferences while an application is open?
Here's where I'm at now:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
// I need to synchronize somewhere in here???
switch (tabBarController.selectedIndex)
{
case 0:
NSLog(@"Tab 0 selected");
break;
case 1:
NSLog(@"Tab 1 selected");
break;
case 2:
NSLog(@"Tab 2 Selected");
break;
}
}
Thanks ahead of time.
回答1:
Try syncing the defaults in viewWillAppear
instead of viewDidLoad
.
It may happen that viewDidLoad
is called multiple times (in which case, viewDidUnload
will have been called between), for example, if there is a memory issue.
By synchronizing the defaults in viewWillAppear
, you are ensuring that the relevant UIViewController
is updated just before it becomes the selected view controller.
回答2:
Rather than force a lot of extra loads by re-syncing on every view display, you can have each of your view controllers register as a notification observer when they get loaded (viewDidLoad), and whereever you change your settings, you post a "settings_changed" notification. (This is an incredibly useful pattern for decoupling objects that need to communicate).
So each of your viewDidLoad methods will have this:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(refreshDefaults)
name:@"Defaults_changed"
object:nil];
The viewDidUnload will unregister the vc:
[[NSNotificationCenter defaultCenter]
removeObserver: self
name: @"Defaults_changed"
object: nil];
Handle the event:
- (void) refreshDefaults {
// re-load your defaults here
}
Any place that makes a change will do this:
[[NSNotificationCenter defaultCenter]
postNotificationName:@"Defaults_changed"
object: nil];
回答3:
You only need to call synchronize
when you've made changes. Every time you call setObject:obj forKey:@"key"
to set the object, call synchronize
directly afterwards.
Also, instead of creating a pointer to NSUserDefaults
try using the shared instance directly, like [[NSUserDefaults standardUserDefaults] objectForKey:@""];
and [[NSUserDefaults standardUserDefaults] setObject:obj forKey:@""];
to set the objects. Then call synchronize
after setting an object.
来源:https://stackoverflow.com/questions/6631442/synchronizing-plist-across-a-tab-bar-application