Iphone NSUserDefaults正确使用和检测更改
我是一个初学者,正在构建一个iOS通用应用程序,它在应用程序生命周期的各个阶段使用NSUserDefaults,包括一个应用程序内页面来设置这些变量。我发现我的UserDefaults经常与UI不同步,编写代码检查这些首选项会变得单调乏味 正如你在下面看到的,我正在检查“使用相机”的偏好是否设置得非常好;一定有更简单的方法 加载允许应用程序内编辑用户首选项的viewController时,情况会变得更糟: 是否有某种方法可以消除一些代码量(从而最大限度地减少内存优化的调试/工作),而不必在很多时候检查首选项的值?我是否应该使用NSUserDefaultsDidChangeNotification检测到更改,并在此通知方法内设置AppDelegate变量? 示例(明显的省略假设这些方法存在…只是与我的偏好无关: 在我的AppDelegate中:Iphone NSUserDefaults正确使用和检测更改,iphone,objective-c,ios4,Iphone,Objective C,Ios4,我是一个初学者,正在构建一个iOS通用应用程序,它在应用程序生命周期的各个阶段使用NSUserDefaults,包括一个应用程序内页面来设置这些变量。我发现我的UserDefaults经常与UI不同步,编写代码检查这些首选项会变得单调乏味 正如你在下面看到的,我正在检查“使用相机”的偏好是否设置得非常好;一定有更简单的方法 加载允许应用程序内编辑用户首选项的viewController时,情况会变得更糟: 是否有某种方法可以消除一些代码量(从而最大限度地减少内存优化的调试/工作),而不必在很多时
#progma mark Application Lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// check values; if not present, set some defaults.
if (![prefs stringForKey:@"pfUseCamera"]) {
[prefs setValue:@"NO" forKey:@"pfUseCamera"];
}
if (![prefs stringForKey:@"pfWorkInBackground"]) {
[prefs setValue:@"NO" forKey:@"pfWorkInBackground"];
}
[prefs synchronize];
self.backgroundTasksTimer = [NSString stringWithString:[prefs stringForKey:@"pfWorkInBackground"]];
self.shouldUseCamera = [NSString stringWithString:[prefs stringForKey:@"pfUseCamera"]];
// start our timer
// chose to run this timer ALL-the-time, dispite the user-preference; instead, see below that the timer method returns based on the user preference.
[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:@selector(backgroundTasks:) userInfo:nil repeats:YES];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// pretty much the same as above
// except NSTimer, which is controlled elsewhere
}
#progma mark AppDelegate-controlled Methods
- (void)backgroundTasks:(NSTimer *)timer {
if (![self.backgroundTasksTimer boolValue]) {
return;
} else {
// do stuff in a timer begun in AppDelegate only if this preference is NOT NO
}
}
我的主视图控制器:
#progma mark ViewController Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate]; // I have this set up in the AppDelegate to allow this
if ([app.shouldUseCamera boolValue]) {
// init the camera and have it ready for use
}
}
- (void)viewDidAppear:(BOOL)animated {
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate]; // I have this set up in the AppDelegate to allow this
if ([app.shouldUseCamera boolValue]) {
// resume the camera capture
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
if ([app.shouldUseCamera boolValue]) {
// suspend the camera capture
}
}
- (void)viewDidUnload {
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
if ([app.shouldUseCamera boolValue]) {
// unload the camera
}
}
#progma mark User/IBAction Methods
-(IBAction)doStuff:(id)sender {
MyAppDelegate *app = [MyAppDelegate *app = [MyAppDelegate sharedAppDelegate]; sharedAppDelegate];
// take a picture
if ([app.shouldUseCamera boolValue]) {
[NSThread detachNewThreadSelector:@selector(takePicture:) toTarget:self withObject:fileName]; // take a photo and do stuff to it in a separate thread
}
}
- (void)viewDidLoad {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
// set UITextField to value of String Preference
someUITextField.text = [prefs stringForKey:@"pfSomeOtherValue"];
// set UISwitch to value of PSToggleSwitchSpecifier
if ([app.backgroundTasksTimer boolValue]) {
[shouldExecuteBackgroundTasks setOn:YES];
} else {
[shouldExecuteBackgroundTasks setOn:NO];
}
// set UISwitch to value of PSToggleSwitchSpecifier
if ([app.shouldUseCamera boolValue]) {
[shouldUseCamera setOn:YES];
} else {
[shouldUseCamera setOn:NO];
}
- (IBAction)done:(id)sender {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
[prefs setObject:companyID.text forKey:@"pfCompanyID"];
if ([shouldUseCamera isOn]) {
[prefs setObject:@"YES" forKey:@"pfUseCamera"];
app.backgroundTasksTimer = @"YES";
} else {
[prefs setObject:@"NO" forKey:@"pfUseCamera"];
app.backgroundTasksTimer = @"NO";
}
if ([shouldExecuteBackgroundTasks isOn]) {
[prefs setObject:@"YES" forKey:@"pfWorkInBackground"];
app.shouldUseCamera = @"YES";
} else {
[prefs setObject:@"NO" forKey:@"pfWorkInBackground"];
app.shouldUseCamera = @"NO";
}
[prefs synchronize];
[self.delegate settingsControllerDidFinish:self];
}
设置可视控制器:
#progma mark ViewController Lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate]; // I have this set up in the AppDelegate to allow this
if ([app.shouldUseCamera boolValue]) {
// init the camera and have it ready for use
}
}
- (void)viewDidAppear:(BOOL)animated {
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate]; // I have this set up in the AppDelegate to allow this
if ([app.shouldUseCamera boolValue]) {
// resume the camera capture
}
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
if ([app.shouldUseCamera boolValue]) {
// suspend the camera capture
}
}
- (void)viewDidUnload {
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
if ([app.shouldUseCamera boolValue]) {
// unload the camera
}
}
#progma mark User/IBAction Methods
-(IBAction)doStuff:(id)sender {
MyAppDelegate *app = [MyAppDelegate *app = [MyAppDelegate sharedAppDelegate]; sharedAppDelegate];
// take a picture
if ([app.shouldUseCamera boolValue]) {
[NSThread detachNewThreadSelector:@selector(takePicture:) toTarget:self withObject:fileName]; // take a photo and do stuff to it in a separate thread
}
}
- (void)viewDidLoad {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
// set UITextField to value of String Preference
someUITextField.text = [prefs stringForKey:@"pfSomeOtherValue"];
// set UISwitch to value of PSToggleSwitchSpecifier
if ([app.backgroundTasksTimer boolValue]) {
[shouldExecuteBackgroundTasks setOn:YES];
} else {
[shouldExecuteBackgroundTasks setOn:NO];
}
// set UISwitch to value of PSToggleSwitchSpecifier
if ([app.shouldUseCamera boolValue]) {
[shouldUseCamera setOn:YES];
} else {
[shouldUseCamera setOn:NO];
}
- (IBAction)done:(id)sender {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
MyAppDelegate *app = [MyAppDelegate sharedAppDelegate];
[prefs setObject:companyID.text forKey:@"pfCompanyID"];
if ([shouldUseCamera isOn]) {
[prefs setObject:@"YES" forKey:@"pfUseCamera"];
app.backgroundTasksTimer = @"YES";
} else {
[prefs setObject:@"NO" forKey:@"pfUseCamera"];
app.backgroundTasksTimer = @"NO";
}
if ([shouldExecuteBackgroundTasks isOn]) {
[prefs setObject:@"YES" forKey:@"pfWorkInBackground"];
app.shouldUseCamera = @"YES";
} else {
[prefs setObject:@"NO" forKey:@"pfWorkInBackground"];
app.shouldUseCamera = @"NO";
}
[prefs synchronize];
[self.delegate settingsControllerDidFinish:self];
}
请看一下本主题,其中介绍了如何注册默认更改的更改通知
如果多个视图需要检查此值,您可以将该值作为应用程序委托的属性公开,并在需要时检查该属性。应用程序委托将订阅通知,并在其触发时重新加载属性值。一种方法是去掉应用程序委托中的字段,只使用NSUserDefaults。我很抱歉不确定这个开销,但是有一个带有静态访问器的“CONFIG”类,也可以考虑使用BoL(和其他)访问器,如:
@implementation Config
+(BOOL)shouldUseCamera {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
return [defaults boolForKey:@"shouldUseCamera"];
}
+(void)setShouldUseCamera:(BOOL)should {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:should forKey:@"shouldUseCamera"];
}
然后从任何地方访问它们都很简单。我将在同一个配置类中使用NSBundle和NSProcessInfo,然后我的应用程序将所有配置都放在一个地方
另外,根据我所读到的,您通常不必调用synchronize