NSUserDefaults will not load after leaving app - objective-c

I set up multiple NSUserDefaults in my app that work for the most part. The NSUserDefaults are called from one ViewController and implemented at another (such as in a game with a level select). This seems to work well, until the user presses the back button on the level select screen. When they try to go back to the level select viewController, the NSUserDefaults are not loaded onto the screen.
Here is my code:
LevelSelectViewController:
- (void)viewDidLoad
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults synchronize];
[super viewDidLoad];
}
- (void)Level1DidFinish:(Level1 *)controller
{
[self dismissModalViewControllerAnimated:YES];
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSInteger rank = [userDefaults integerForKey:#"levelRank"];
{
if (rank == 1) {
button2.hidden = NO;
}
}
}
Level1ViewController:
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:1 forKey:#"levelRank"];
}

You need to call [userDefaults synchronize] after setting a value for a key. The automatic synchronization happens quite rarely, so in this case, while one completes a level, the sync won't have yet happened.
So modify your code like this:
Level1ViewController:
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:1 forKey:#"easyRank"];
[userDefaults synchronize];
}

Your first issue is you are creating an instance of userDefaults, but are not setting any values. So calling synchronize here is actually doing nothing:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults synchronize];
After you set a your Integer, then you need to call synchronize:
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setInteger:1 forKey:#"easyRank"];
[userDefaults synchronize];

You're setting values for two different keys. What are you expecting to happen?
Either Level1ViewController needs to set a value for levelRank or LevelSelectViewController needs to read the value for the easyRank key.

Related

Objective c function with variable [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Could you, please, help.
I have a lot of different savings like this
SaveFBProfilePicture1 = ProfilePicture1.stringValue;
DefaultProfilePicture1 = [NSUserDefaults standardUserDefaults];
[DefaultProfilePicture1 setObject:SaveFBProfilePicture1 forKey:#"SaveProfilePicture1"];
[DefaultProfilePicture1 synchronize];
SaveFBProfilePicture2 = ProfilePicture2.stringValue;
DefaultProfilePicture2 = [NSUserDefaults standardUserDefaults];
[DefaultProfilePicture2 setObject:SaveFBProfilePicture2 forKey:#"SaveProfilePicture2"];
[DefaultProfilePicture2 synchronize];
SaveFBAlbums2 = Albums2.stringValue;
DefaultAlbums2 = [NSUserDefaults standardUserDefaults];
[DefaultAlbums2 setObject:SaveFBAlbums2 forKey:#"SaveAlbums2"];
[DefaultAlbums2 synchronize];
SaveFBAbout1 = About1.stringValue;
DefaultAbout1 = [NSUserDefaults standardUserDefaults];
[DefaultAbout1 setObject:SaveFBAbout1 forKey:#"SaveAbout1"];
[DefaultAbout1 synchronize];
SaveFBAbout2 = About2.stringValue;
DefaultAbout2 = [NSUserDefaults standardUserDefaults];
[DefaultAbout2 setObject:SaveFBAbout2 forKey:#"SaveAbout2"];
[DefaultAbout2 synchronize];
And I don't know how it is possible to create function for this.
I need to have a function
- (void)SaveFB {
SaveFBxy = xy.stringValue;
Defaultxy = [NSUserDefaults standardUserDefaults];
[Defaultxy setObject:SaveFBxy forKey:#"Savexy"];
[Defaultxy synchronize];}
Where i can easiely change "x" to, for example, "About" or "Albums" and "y" to "1" or "2"
Please, help me.
And thank you in advance!
- (void)SaveFB:(NSString *)x:(NSString *)y
{
NSString *value=[NSString stringWithFormat:#"%#%#",x,y];
NSString *key=[NSString stringWithFormat:#"Save%#%#",x,y];
NSUserDefaults *defaultxy = [NSUserDefaults standardUserDefaults];
[defaultxy setObject:value forKey:key];
[defaultxy synchronize];
}
It would seem to be pretty basic;
void setUserDefault(NSString* key, NSString* value) {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:value forKey:key];
[userDefaults synchronize];
}
...or as a class method;
+ (void) setUserDefault:(NSString*)key toValue:(NSString*)value {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:value forKey:key];
[userDefaults synchronize];
}
If setting multiple values at once, you may not want to synchronize for every single value though, it may be better to just do;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:ProfilePicture1.stringValue forKey:#"SaveProfilePicture1"];
[userDefaults setObject:ProfilePicture2.stringValue forKey:#"SaveProfilePicture2"];
[userDefaults setObject:Albums2.stringValue forKey:#"SaveAlbums2"];
[userDefaults setObject:About1.stringValue forKey:#"SaveAbout1"];
[userDefaults setObject:About2.stringValue forKey:#"SaveAbout2"];
[userDefaults synchronize];
(synchronize is also called automatically periodically, so you may not need it at all unless you're doing this right at app exit)

NSUserDefaults Reset First Run

I have an app already in the AppStore that uses NSUserDefaults. Some of the defaults are Default settings that I go ahead and set when the app is first launched, and then the user is allowed to change them later if they wish. So, in my AppDelegate appDidFinishLaunchingWithOptions I put:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (! [defaults boolForKey:#"notFirstRun"]) {
[defaults setBool:YES forKey:#"notFirstRun"];
[defaults setInteger:0 forKey:#"verseKey"];
[defaults synchronize];
}
The issue I am having now is I want to add some more Default settings in the NSUserDefault category, so I want to make it look like this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (! [defaults boolForKey:#"notFirstRun"]) {
[defaults setBool:YES forKey:#"notFirstRun"];
NSString *smalltitle = #"4";
NSString *smallarticle = #"3";
[defaults setObject:smalltitle forKey:#"Title"];
[defaults setObject:smallarticle forKey:#"Article"];
[defaults setInteger:0 forKey:#"verseKey"];
[defaults synchronize];
}
I know that this will cause an issue for those who have already downloaded the app, and are merely updating it. They will not run that code because the notFirstRun Bool has already been set to YES. Any thoughts on what I should do here?
The proper solution is to not actually populate NSUserDefaults with default values. Instead, use the registerDefaults: method.
At app startup you do:
NSUserDefaults *default = [NSUserDefaults standardUserDefaults];
[defaults registerDefaults:#{
#"Title" : #"4",
#"Article" : #"3",
#"verseKey" : #0
}];
That's it. Call this every time the app is run. These defaults are not actually persisted. The value is only returned if there isn't already an explicit value for the key. You can update these defaults all you want without affecting any existing values.
Make a new notFirstRun Boolean value (i.e. notFirstRunTwo). That will be 'NO' for existing users, too.
I suggest to do the following :
check userdefaults for stored app version if it is equal to the current or not , if not.
store the current app version and do your first launch initialization
the code
`
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *appVersion = [NSString stringWithFormat:#"%#",[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleShortVersionString"]];
if (! [defaults objectForKey:appVersion ])
{
/// store the current version and then do your first run functions
[defaults setObject:[NSNumber numberWithInt:1] forKey:appVersion];
/// here do your first run
......
}`

Checking if view controller has been loaded before

I am trying to checking if a certain view has been loaded ever before in the lifetime of the app. I have implemented the following code but not quite sure why it isn't working. It is being done in the viewDidLoad method only of the view controller (perhaps this is the problem). If anyone can let me know what my mistake is, it would be appreciated. Thanks!
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL hasRunBefore = [defaults boolForKey:#"FirstRun"];
if (hasRunBefore) {
NSLog (#"not the very first time this controller has been loaded");
[defaults setBool:YES forKey:#"FirstRun"];
[defaults synchronize];
}
else if (!hasRunBefore) {
[defaults setBool:NO forKey:#"FirstRun"];
NSLog (#"the very first time this controller has been loaded");
[defaults synchronize];
}
There are a couple of mistakes in your code. See the corrections below:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL hasRunBefore = [defaults boolForKey:#"FirstRun"];
if (hasRunBefore) {
NSLog (#"not the very first time this controller has been loaded");
/* Toggle the boolean state */
[defaults setBool:NO forKey:#"FirstRun"];
}
else if (!hasRunBefore) {
/* Toggle the boolean state */
[defaults setBool:YES forKey:#"FirstRun"];
NSLog (#"the very first time this controller has been loaded");
}
[defaults synchronize];
However, I am not sure why you would want to toggle the FirstRun back to NO in the if(hasRunBefore). I only point out what is wrong, you might want to check your logic again.
-EDIT-
Like I pointed out about your logic, you should only have this:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL hasRunBefore = [defaults boolForKey:#"FirstRun"];
if (!hasRunBefore) {
[defaults setBool:YES forKey:#"FirstRun"];
[defaults synchronize];
NSLog (#"the very first time this controller has been loaded");
}
else
NSLog (#"Not the first time this controller has been loaded");
The values set in defaults are persistent for as long as the app is installed on the device.
You should think about using a BOOL value set in the app delegate (which does not persist from run to run)
OR
You should set "FirstRun" back to NO in your app delegate in the following method.
- (void)applicationWillTerminate:(UIApplication *)application
NSUserDefaults is a possibility, but you could also use a static BOOL and set it to YES when the view controller is loaded for the first time.

Saving hidden button state using NSUserDefaults Error

Trying to save button state as hidden when navigating off the view controller.
under IBAction
btnonce.hidden = YES;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:Act1Button.hidden forKey:#"isHidden"];
Calling it in ViewDidLoad
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
btnonce.hidden = [userDefaults valueForKey:#"isHidden"];
I'm getting the error: Implicit conversion of "BOOL" (aka signed char) to ID is disallowed with ARC
How to rectify this?
For saving the Bool value in NSUserDefaults use this code
[defaults setBool:Act1Button.hidden forKey:#"isHidden"];
For retrieving use this
btnonce.hidden = [userDefaults boolForKey:#"isHidden"];

NSUserDefaults not saving in table cell

When I replace the #"hello" with titlestring the table, the cell shows up blank, If i leave the hello, everything works, including the "detailsstring". I don't know why it's doing that since detailsstring is set up exactly the same as titlestring.
here is the code:
in the .m file I have
#synthesize detailsstring;
#synthesize titlestring;
and it's all defined the same in the .h in the .m I have this as well:
- (void)viewDidLoad{
titlestring =[[NSUserDefaults standardUserDefaults] objectForKey:#"titletext"];
detailsstring = [[NSUserDefaults standardUserDefaults] objectForKey:#"details"];
tabledata = [[NSArray alloc] initWithObjects:#"hello", nil];
tablesubtitles = [[NSArray alloc] initWithObjects:detailsstring, nil];
[super viewDidLoad];
}
Now, I'm saving those Userdefaults in another controller. Here is the save button action in a different view controller:
- (IBAction)saveButton:(id)sender {
NSUserDefaults *titletext = [NSUserDefaults standardUserDefaults];
[titletext setObject:titleTextfield.text forKey:#"titletext"];
NSUserDefaults *details = [NSUserDefaults standardUserDefaults];
[details setObject:detailstextfield.text forKey:#"details"];
NSUserDefaults *categoryUser = [NSUserDefaults standardUserDefaults];
[categoryUser setInteger:selectedCategory forKey:#"category"];
}
What am I doing wrong?
First of all, one instance of NSUserDefaults is sufficient for all three modifications. To 'push' the changes to the file system immediately, you can call [userDefaults synchronize];. Otherwise there is no guarantee that your changes are saved instantly. Apple suggests only to call this method if you cannot wait for the changes to be saved.
- (IBAction)saveButton:(id)sender {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:titleTextfield.text forKey:#"titletext"];
[userDefaults setObject:detailstextfield.text forKey:#"details"];
[userDefaults setInteger:selectedCategory forKey:#"category"];
[userDefaults synchronize];
}
In your viewDidLoad: method, try to output the saved values to test your application's integrity:
NSLog(#"%#", [[NSUserDefaults standardUserDefaults] objectForKey:#"details"]);