Using NSUserDefaults for storing UISwitch state - iphone

I am trying to persist the UISwitch state in my settings view of my application. Basically it is a UITableView and contains a few switches to get the user preferences. The below code explains how the switches are constructed (only one switch construct is given below, others are also constructed the sameway).
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SomeIdentifierB] autorelease];
if (syncStartupSwitch) {
syncSwitch.on = YES;
}else {
syncSwitch.on = NO;
}
[syncSwitch addTarget:self action:#selector(syncAtStartup:) forControlEvents:UIControlEventValueChanged];
NSLog(#"Why is this not working%#",(syncSwitch.on ? #"YES" : #"NO"));
[cell.contentView addSubview:syncSwitch];
cell.accessoryView = syncSwitch;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//cell.reuseIdentifier = #"Cell1";
}
cell.textLabel.text =cellValue;
return cell;
}
Now, I would like to store the state of the Switches using NSUserDefaults. So in my selector method implementation, I defined the NSUserDefaults like this:
-(void) syncAtStartup:(id)sender {
if ([sender isOn]) {
[[NSUserDefaults standardUserDefaults]
setObject:#"YES" forKey:#"SyncAtStartup"];
[[NSUserDefaults standardUserDefaults]synchronize];
NSLog(#"%#",(syncStartupSwitch ? #"YES" : #"NO"));
}else {
[[NSUserDefaults standardUserDefaults]
setObject:#"NO" forKey:#"SyncAtStartup"];
//syncStartupSwitch = [[NSUserDefaults standardUserDefaults]boolForKey:#"SyncAtStartup"];
}
}
Finally, in my viewDidLoad I wrote this line of code:
syncStartupSwitch = [[NSUserDefaults standardUserDefaults]boolForKey:#"SyncAtStartup"];
I am sure there is some missing logic to my implementation. Can somebody point out the flaw and correct me?
UPDATE:
I took the suggestion from #jfalexvijay and used the below code:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SyncAtStartup"];
BOOL syncStartupSwitch = [[NSUserDefaults standardUserDefaults] boolForKey:#"SyncAtStartup"];
When I look into the Preferences folder, I see the plist getting created with the BOOL value in it. I then try to set the UISwitch state in cellForRowAtIndexPath method like this:
syncSwitch.on = syncStartupSwitch;
I also have this line of code in ApplicationWillTerminate and in the selector itself
[[NSUserDefaults standardUserDefaults]synchronize];
Still, after restarting the application on the simulator or device, the switch state is not restored...
What is my mistake in the above code?
Cheers,
iSee

you can use following code;
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"SyncAtStartup"];
BOOL test = [[NSUserDefaults standardUserDefaults] boolForKey:#"SyncAtStartup"];
if you use following code, it will return YES;
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"SyncAtStartup"];
BOOL test = [[NSUserDefaults standardUserDefaults] boolForKey:#"SyncAtStartup"];
Just test above code;

Instead of using setObject:forKey: try using setBool:forKey:.
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"SyncAtStartup"];

Related

Saving and Loading settings by NSUserDefault on UIswitches Xcode

I have a settings view where i have provided the option for users to change their settings.
Settings view have a table view having 2 UISwitches. I need help with NSUserdefaults method for saving states, and how I can write the code to load my values.
Here is my code so far
In `cellForRowAtIndexPath` method:
[cell.switchButton addTarget:self action:#selector(switchButtonTapped:) forControlEvents:UIControlEventValueChanged];
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"myBool"];
BOOL hBool = [[ NSUserDefaults standardUserDefaults] boolForKey:#"myBool"];
NSLog(#"tag %i", tappedSwitch.tag);
if (cell.switchButton.tag == 0) {
[cell.switchButton setOn:hBool];
}
return cell;
}
- (void) switchButtonTapped: (id) sender {
tappedSwitch = (UISwitch *) sender;
switch (tappedSwitch.tag) {
case 0:
passcodeSwitchIsOn = tappedSwitch.isOn;
if (passcodeSwitchIsOn) {
GCPINViewController *PIN = [[GCPINViewController alloc]
initWithNibName:nil
bundle:nil
mode:GCPINViewControllerModeCreate];
PIN.messageText = #"Enter a passcode";
PIN.errorText = #"The passcodes do not match";
PIN.title = #"Set Passcode";
PIN.verifyBlock = ^(NSString *code) {
NSLog(#"setting code: %#", code);
code = saveString;
return YES;
};
[PIN presentFromViewController:self animated:YES];
[PIN release];
// method of saving
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:passcodeSwitchIsOn forKey:#"myBool"];
[defaults synchronize];
}
break;
case 1:
bluetoothSwitchIsOn = tappedSwitch.isOn;
if (bluetoothSwitchIsOn) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Bluetooth Switch" message:#"Bluetooth Switch is ON" delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
break;
default:
break;
}
[settingsTable reloadData];
}
Create a reference to your user defaults:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
Set a value:
[defaults setBool:1 forKey:#"bluetooth"];
You can set this back to 0 when bluetooth is off:
[defaults setBool:0 forKey:#"bluetooth"];
The user default is identified by the string of your choice. In this case: #"bluetooth". The value for the default will be nil until you create it and set it to something else.
So you can say:
if (!bluetooth) // bluetooth is off
else // bluetooth is on
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
This can be used for handling your issue.
IBOutlet UISwitch * swi_yourswitch;
#property(nonatomic,retain) UISwitch * swi_yourswitch;
implimentation
#synthesise swi_yourswitch;
- (void) switchButtonTapped: (id) sender {
UISwitch * switchObj = (UISwitch*)sender;
if(switchObj == self.swi_yourswitch){
if (self.swi_yourswitch.on){
NSLog(#"On");
}
else{
NSLog(#"Off");
[self.swi_yourswitch setOn:0];
}
}
To store value
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"mybool"];
[[NSUserDefaults standardUserDefaults] synchronize];
To get stored value
[NSUserDefaults standardUserDefaults] valueForKey:#"mybool"]

How to add NSUserDefault data to a UITextField?

I have 3 UIVIewControllers that have NSUsuerDefaults to store data. My 4th UIViewController is used to display the total data collected between the first 3 UIViewControllers. How do I collect the data and display it in a UITextfield? Here is an example of my NSUserDefault code that I'm using:
[tex setText:[[NSUserDefaults standardUserDefaults] objectForKey:#"storedTextValue1"]];
[tex setText:[[NSUserDefaults standardUserDefaults] objectForKey:#"storedTextValue22"]];
[tex setText:[[NSUserDefaults standardUserDefaults] objectForKey:#"storedTextValue43"]]; I want to add this collected data to a UITextfield on my 4th UIViewController.
Try this:
textField.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"storedTextValue1"];
Or
NSString *storedValue1 = [[NSUserDefaults standardUserDefaults] objectForKey:#"storedTextValue1"];
textField.text = storedValue1;
I think you should use
tex setText:[[NSUserDefaults standardUserDefaults] valueForKey:#"storedTextValue43"];
So basically you need to use valueForKey: in place of objectForKey:
Hope this helps you.
EDIT:
[text setText:[NSString stringWithFormat:#"%# %# %#",[[NSUserDefaults standardUserDefaults] valueForKey:#"storedTextValue43"],[[NSUserDefaults standardUserDefaults] valueForKey:#"storedTextValue1"],[[NSUserDefaults standardUserDefaults] valueForKey:#"storedTextValue22"]]];
EDIT-2:
UITextField(Total) is Say txtTotal
UITextField(storetext1) is say txtStore1
UITextField(storetext2) is say txtStore2
UITextField(storetext3) is say txtStore3
Now simply do this as
int sum = [txtStore1.text intValue] + [txtStore2.text intValue] + [txtStore3.text intValue]
txtTotal.text = [NSString stringWithFormat:#%d",sum];

How to save value in the plist and acces the plist?

I have a UITableView with a UISwitch button in it. I want that when I run my application default value of the UISwitch button should be ON. If I toggle the switch button from on to off the value in the plist should change to OFF. If I quit the app and then I again run my app the value should again default to ON in the plist.
I have tried using NSUserDefaults, it works i.e when I change the value from ON to OFF the value in NSUserDefaults also changes. But when the app is run again the default value is not set to ON.
- (void)viewDidLoad {
[super viewDidLoad];
settings = [[NSMutableArray alloc]initWithObjects:#"Clock",#"Time Format",#"Weather",#"Degrees",nil];
switchControl = [[UISwitch alloc]initWithFrame:CGRectMake(205, 110, 20, 15) ];
[self.switchControl addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:switchControl];
NSString *viewdid = #"ON";
userdefaults = [NSUserDefaults standardUserDefaults];
[userdefaults setObject:viewdid forKey:#"stateOfSwitch"];
}
- (void)viewWillAppear:(BOOL)animated {
NSString *_value= [[NSUserDefaults standardUserDefaults] stringForKey:#"stateOfSwitch"];
if([_value compare:#"ON"] == NSOrderedSame){
[switchControl setOn:YES animated:YES];
}
else {
[switchControl setOn:NO animated:YES];
}
[super viewWillAppear:animated];
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return 4;
}
-(void)switchChanged:(id)sender
{
app= (StopSnoozeAppDelegate*)[[UIApplication sharedApplication]delegate];
NSString *value = #"ON";
userdefaults = [NSUserDefaults standardUserDefaults];
if(!switchControl.on){
value = #"OFF";
[userdefaults setObject:value forKey:#"stateOfSwitch"];
}
[userdefaults setObject:value forKey:#"stateOfSwitch"];
[userdefaults synchronize];
}
//this is my second class where i am accessing my userdefaults key and depending on that hiding the views
- (void) viewWillAppear:(BOOL)animated
{
NSString *_value= [[NSUserDefaults standardUserDefaults] stringForKey:#"stateOfSwitch"];
if([_value compare:#"ON"] == NSOrderedSame){
newview.hidden = NO;
newnewview.hidden =NO;
firstview.hidden = NO;
secondview.hidden = NO;
thirdview.hidden = NO;
}
else if([_value compare:#"OFF"] == NSOrderedSame) {
newview.hidden = YES;
newnewview.hidden= YES;
firstview.hidden = YES;
secondview.hidden = YES;
thirdview.hidden = YES;
}
}
In appDelegate did finish loading write below statements
[[NSUserDefaults standardUserDefaults] setObject:#"OFF" forKey:#"stateOfSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
May be you have not dump new values to plist?
Try to call [[NSUserDefaults standardUserDefaults] synchronize]; after setting new value to NSUserDefaults.
Either do
// set when launching the app
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[[NSUserDefaults standardUserDefaults] setObject:#"OFF" forKey:#"stateOfSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
or
// set when terminating
- (void)applicationWillTerminate:(UIApplication *)application
[[NSUserDefaults standardUserDefaults] setObject:#"OFF" forKey:#"stateOfSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Furthermore, you should test your NSString using isEqualToString: as compare: may lead to false positives (e.g. if one of the strings is nil).
You shouldn't store a string, which has the potential for parsing bugs, when NSUserDefaults is perfectly capable of storing BOOLs directly.
Just store it like this:
#define StateOfSwitch #"StateOfSwitch"
-(void)switchChanged:(id)sender
{
[[NSUserDefaults standardUserDefaults] setBool:switchControl.on forKey:StateOfSwitch];
[[NSUserDefaults standardUserDefaults] synchronize];
}
and then later, load the value like this:
switchControl.on = [[NSUserDefaults standardUserDefaults] boolForKey:StateOfSwitch];
(Note it's a good idea to never use string keys directly, it's better to #define them to prevent typo errors. Plus you get command + click to jump to definition, autocompletion, etc.)

Having an NSUserDefault Problem

I am trying to save a couple of preferences in a program I can't seem to make NSUserDefaults work properly. If someone could take a look at my code and see if there are any errors it would be appreciated
NSString *kGameIsPaused = #"gameGameIsPaused";
NSString *kSoundOn = #"gameSoundOn";
NSString *kMusicOn = #"gameMusicOn";
NSString *kHighScore = #"gameHighScore";
- (void)saveGameState
{
[[NSUserDefaults standardUserDefaults] setBool:gameIsPaused forKey:kGameIsPaused];
[[NSUserDefaults standardUserDefaults] setBool:soundOn forKey:kSoundOn];
[[NSUserDefaults standardUserDefaults] setBool:musicOn forKey:kMusicOn];
[[NSUserDefaults standardUserDefaults] setInteger:highScore forKey:kHighScore];
}
-(void)loadGameState
{
gameIsPaused = [[NSUserDefaults standardUserDefaults] boolForKey:kGameIsPaused];
soundOn = [[NSUserDefaults standardUserDefaults] boolForKey:kSoundOn];
musicOn = [[NSUserDefaults standardUserDefaults] boolForKey:kMusicOn];
highScore= [[NSUserDefaults standardUserDefaults] integerForKey:kHighScore];
if (soundOn == NO) {
[soundToggle setImage:[UIImage imageNamed:#"SoundOFF.png"] forState:UIControlStateNormal];
}
if (musicOn == NO) {
[musicToggle setImage:[UIImage imageNamed:#"MusicOff.png"] forState:UIControlStateNormal];
}
}
they everytime i run the loadGameState method I get returned the default values as if there is no key to reference.
Inside of saveGameState I would recommend adding a synchronize to your defaults to persist them. If your game is crashing or you are stopping the debugger or anything else goes wrong they may not get saved properly.
- (void)saveGameState
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:gameIsPaused forKey:kGameIsPaused];
[defaults setBool:soundOn forKey:kSoundOn];
[defaults setBool:musicOn forKey:kMusicOn];
[defaults setInteger:highScore forKey:kHighScore];
[defaults synchronize];
}

Can't read NSUserDefaults data between views

Disclaimer: major noob
I'm writing an arithmetic flash card app as a learning project. I have a UITabViewController with the bottom tab bar that toggles between a few different views. Everything works okay until I try to set NSUserDefault boolean values in the Settings view controller and try to read those values in the Flashcards view controller.
The settings view has a switch to enable/disable each operator (addition, subtraction, etc) and the flashcard view should randomly present a flash card if that type of operation was enabled.
I believe that my mistake is that I don't understand the key concept of data encapsulation, objects, etc. I'd appreciate any help.
Here is the Settings view controller. I'm not even sure how to put the code into this forum so this might be a laughable moment... here goes:
// settings_flashcards.h
#import <UIKit/UIKit.h>
#interface settings_flashcards : UIViewController {
UISwitch *additionSwitch;
UISwitch *subtractionSwitch;
UISwitch *multiplicationSwitch;
UISwitch *divisionSwitch;
}
#property (nonatomic,retain) IBOutlet UISwitch *additionSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *subtractionSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *multiplicationSwitch;
#property (nonatomic,retain) IBOutlet UISwitch *divisionSwitch;
#end
and...
/ settings_flashcards.m
#import "settings_flashcards.h"
#implementation settings_flashcards
#synthesize additionSwitch;
#synthesize subtractionSwitch;
#synthesize multiplicationSwitch;
#synthesize divisionSwitch;
- (void)viewDidLoad {
[additionSwitch addTarget:self action:#selector(additionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[subtractionSwitch addTarget:self action:#selector(subtractionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[multiplicationSwitch addTarget:self action:#selector(multiplicationSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[divisionSwitch addTarget:self action:#selector(divisionSwitchFlipped) forControlEvents:UIControlEventValueChanged];
[super viewDidLoad];
}
-(void) additionSwitchFlipped {
if (additionSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"additionKey"];
}
}
-(void) subtractionSwitchFlipped {
if (subtractionSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"subtractionKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"subtractionKey"];
}
}
-(void) multiplicationSwitchFlipped {
if (multiplicationSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"multiplicationKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"multiplicationKey"];
}
}
-(void) divisionSwitchFlipped {
if (divisionSwitch.on) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"divisionKey"];
}else {
[[NSUserDefaults standardUserDefaults] setBool:FALSE forKey:#"divisionKey"];
}
}
Here is the Flashcards view...
// flashcardsViewController.h
#import <UIKit/UIKit.h>
#interface flashcardsViewController : UIViewController <UIActionSheetDelegate>{
UILabel *firstNumberLabel;
UILabel *secondNumberLabel;
UILabel *answerNumberLabel;
UILabel *operatorLabel;
BOOL additionIsEnabled;
BOOL subtractionIsEnabled;
BOOL multiplicationIsEnabled;
BOOL divisionIsEnabled;
}
#property (nonatomic,retain) IBOutlet UILabel *firstNumberLabel;
#property (nonatomic,retain) IBOutlet UILabel *secondNumberLabel;
#property (nonatomic,retain) IBOutlet UILabel *answerNumberLabel;
#property (nonatomic,retain) IBOutlet UILabel *operatorLabel;
-(void) buttonClicked:(id)sender;
#end
and...
// flashcardsViewController.m
#import "flashcardsViewController.h"
#implementation flashcardsViewController
#synthesize firstNumberLabel;
#synthesize secondNumberLabel;
#synthesize answerNumberLabel;
#synthesize operatorLabel;
- (void)viewDidLoad {
srand(time(0)); //seed random
//the following should assign the keys if they don't exist
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"additionKey"]){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"subtractionKey"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"subtractionKey"];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"multiplicationKey"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"multiplicationKey"];
}
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"divisionKey"]) {
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"divisionKey"];
}
//the following should assign each BOOL variable based on the key
additionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"additionKey"];
subtractionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"subtractionKey"];
multiplicationIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"multiplicationKey"];
divisionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:#"divisionKey"];
[super viewDidLoad];
}
-(void) buttonClicked:(id)sender{
int a = rand() % 4;// random number generator (number to enter loop)
if ( additionIsEnabled || subtractionIsEnabled || multiplicationIsEnabled || divisionIsEnabled) {
while (a < 5) {
switch (a) {
case 0:
if (additionIsEnabled == TRUE){
int x = rand() % 11 + 1;
int y = rand() %11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x+y)];
operatorLabel.text = [[NSString alloc]initWithFormat: #"+"];
a = 5;
}
else a++;
break;
case 1:
if (subtractionIsEnabled == TRUE){
int x = rand() % 19 + 1;
int y = rand() %11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x-y) ];
operatorLabel.text = [[NSString alloc]initWithFormat: #"-"];
a = 5;
}
else a++;
break;
case 2:
if (multiplicationIsEnabled == TRUE){
int x = rand() % 11 + 1;
int y = rand() %11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x*y)];
operatorLabel.text = [[NSString alloc]initWithFormat: #"×"];
a = 5;
}
else a++;
break;
case 3:
if (divisionIsEnabled == TRUE){
int x = rand() % 11 + 1;
int y = rand() % 11 + 1;
firstNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",(x*y)];
secondNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",y];
answerNumberLabel.text = [[NSString alloc]initWithFormat: #"%i",x];
operatorLabel.text = [[NSString alloc]initWithFormat: #"÷"];
a = 5;
}
else a = 0;
break;
default:
break;
}
}
}
else
{
UIAlertView *noOperatorSelectedAlert = [[UIAlertView alloc]initWithTitle:#"You have not set any operations."
message:#"Return to the settings menu and decide which operations you wish to perform. (addition, subtraction, etc.)"
delegate:self
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[noOperatorSelectedAlert show];
[noOperatorSelectedAlert release];
}
}
There are a few things to do here. Firstly you want a better way of saying what the default state is before the user has made any explicit decisions. Next you want to know when you should refresh your in-app state from user preferences.
Defaults Initialization
The first item's solution is to put the default values into the registration domain for your user preferences. This is something you'll do during application initialization, rather than having your views individually check preferences and update them at initialization time. The preferences system looks in quite a few places for data, and the first place it looks is in the in-memory-only registration domain. This is where you'll put the default (i.e. no value specified means 'x') values for each of your user preferences.
The API you'll use for this is -[NSUserDefaults registerDefaults:], which takes an NSDictionary of values. To set your default values of YES (in Objective-C the BOOL type uses YES and NO rather than TRUE and FALSE) you'll use something like this, commonly executed in a +initialize method for your application's main class:
+ (void) initialize
{
// in any +initialize, make sure it's being called on your class
// +initialize is different from all other methods in this respect
if ( [self isKindOfClass: [MyApplicationDelegate class]] == NO )
return; // being called on a superclass, don't do my stuff
// set up default values for certain preferences
NSMutableDictionary * defaults = [NSMutableDictionary new];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"additionKey"];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"subtractionKey"];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"multiplicationKey"];
[defaults setObject: [NSNumber numberWithBool: YES] forKey: #"divisionKey"];
// set this as the registration domain
[[NSUserDefaults standardUserDefaults] registerDefaults: defaults];
[defaults release];
}
Usually you'll put everything into one method like this, so if you have other parts of the application which expect a default non-zero value for any preference, you should add those to this group and place it into your application delegate's +initialize method.
Now, when your other classes use [[NSUserDefault standardUserDefaults] boolForKey: #"additionKey"] and there is nothing saved to the preference files for that key, they will get the value supplied above.
Refreshing Cached Values
So, you have a view where the user is able to change these preferences. Your next job is to make the view above that update its member variables using the new preferences. For this we can use either delegation or notification. In this case, I'll go with notifications for to reasons:
You're using NSUserDefaults, which can theoretically change in many different places. Delegation would only inform you of changes made by one object.
NSUserDefaults already implements a handy notification which you can watch.
So, in your flashcardsViewController you'll have something like these few methods:
- (void) updateFromPreferences
{
// fetch current values from user defaults into your member variables
additionIsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey: #"additionKey"];
// etc...
}
- (void) viewWillLoad
{
// load variables from user defaults
[self updateFromPreferences];
// find out when the preferences have been changed
// this will cause -updateFromPreferences to be called
// whenever something changes preferences, inside the app or outside
[[NSNotificationCenter defaultNotificationCenter] addObserver: self
selector: #selector(updateFromPreferences)
name: NSUserDefaultsDidChangeNotification
object: nil];
}
- (void) viewDidUnload
{
// always remove notification observers.
[[NSNotificationCenter defaultNotificationCenter] removeObserver: self
name: NSUserDefaultsDidChangeNotification
object: nil];
}
- (void) dealloc
{
// add this to your existing dealloc routine
[[NSNotificationCenter defaultNotificationCenter] removeObserver: self
name: NSUserDefaultsDidChangeNotification
object: nil];
}
Summary
Taken together, these two should give you everything you need to make this work.
In addition to the "always YES" problem pointed out by Chiefly Izzy, your -buttonClicked: method does not read new values from NSUserDefaults. These values are read (once) in [flashcardsViewController viewDidLoad]. If they are changed in settings, the change will not be detected in flashCardsViewController until the next time it is loaded (probably the next time the application is launched).
The simplest approach would be to move your code for reading the IsEnabled BOOL values into the -buttonClicked method, like so:
-(void) buttonClicked:(id)sender {
// the following should assign each BOOL variable based on the key
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
additionIsEnabled = [defaults boolForKey:#"additionKey"];
subtractionIsEnabled = [defaults boolForKey:#"subtractionKey"];
multiplicationIsEnabled = [defaults boolForKey:#"multiplicationKey"];
divisionIsEnabled = [defaults boolForKey:#"divisionKey"];
int a = rand() % 4;
if ( additionIsEnabled || subtractionIsEnabled ...
This code ...
//the following should assign the keys if they don't exist
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"additionKey"]){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}
... simply always set's additionKey to TRUE. If you would like to check if additionKey is set, do this ...
//the following should assign the keys if they don't exist
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"additionKey"]){
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:#"additionKey"];
}
... boolForKey: documentation: If a boolean value is associated with defaultName in the user defaults, that value is returned. Otherwise, NO is returned.
Translated to human language - if there's an value associated with additionKey, this value is returned. If there's no associated value, NO/FALSE is returned.
So, your code does this - if value is not associated with additionKey or if it is set to NO, set it to YES. This leads to this - additionKey is always set to YES/TRUE.