我是一个初学者,并构建一个iOS Universal应用程序,它在应用程序生命周期的各个阶段使用NSUserDefaults - 包括一个用于设置这些变量的应用程序内页面。我发现我的UserDefaults经常与UI不同步,编写代码来检查这些首选项会很繁琐。
如下所示,我正在检查“使用相机”首选项是否设置了很多;必须有一个更简单的方法......?
当我们加载允许应用内编辑用户首选项的viewController时,情况会更糟:
是否有某种方法可以消除一些代码量(因此,最大限度地减少内存优化的调试/工作量),而不是必须在很多时候检查首选项的值?我是否应该使用NSUserDefaultsDidChangeNotification检测到更改,并在此通知方法中设置一次AppDelegate变量? 示例(显而易见的遗漏假定那些方法存在......与我的偏好无关:
在我的AppDelegate中:
#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
}
}
我的主要ViewController:
#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
}
}
SettingsViewController:
- (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];
}
答案 0 :(得分:2)
一种方法是删除应用委托中的字段,然后使用NSUserDefaults。我不确定这有什么开销但是有一个带有静态访问器的“Config”类。此外,您可以考虑使用bool(和其他)访问器,如:
@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"];
}
然后从任何地方访问这些都是蛋糕。我将在同一个Config类中使用NSBundle和NSProcessInfo,然后我的应用程序只有一个地方可用于所有配置。
另外,根据我的阅读,您通常不必调用同步。
答案 1 :(得分:0)
查看此主题,该主题通过注册默认更改的更改通知。 Nsuserdefaultschange
如果多个视图需要检查此值,您可以将值公开为应用委托的属性,并在需要时检查该属性。应用程序委托将订阅通知并在触发时重新加载属性值。