NSUserDefaults правильное использование и обнаружение изменений - PullRequest
0 голосов
/ 14 апреля 2011

Я немного новичок и создаю универсальное приложение для iOS, которое использует NSUserDefaults на различных этапах жизненного цикла приложения, включая страницу в приложении для установки этих переменных. Я обнаружил, что мои UserDefaults часто не синхронизированы с пользовательским интерфейсом, и становится утомительно писать код для проверки этих предпочтений.

Как вы можете видеть ниже, я проверяю, установлен ли параметр «Использовать камеру» очень много; должен быть более легкий путь ...?

Хуже, когда мы загружаем 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];
}

Ответы [ 2 ]

2 голосов
/ 14 апреля 2011

Один из подходов - избавиться от полей в делегате приложения и просто использовать 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"];
    }

Тогда это торт для доступа к ним из любой точки мира. Я буду использовать NSBundle и NSProcessInfo в одном классе Config, а затем в моем приложении будет одно место для всех настроек.

Кроме того, из того, что я прочитал, обычно нет необходимости вызывать синхронизацию.

0 голосов
/ 14 апреля 2011

Взгляните на эту тему, в которой регистрируется уведомление об изменениях по умолчанию. Nsuserdefaultschange

Если нескольким представлениям необходимо проверить это значение, вы можете просто предоставить это значение как свойство делегата приложения и проверить это свойство при необходимости. Делегат приложения подписывается на уведомление и перезагружает значение свойства при его запуске.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...