I'm trying to use NSUserDefaults to save two variables after app shutdown. One being firstBoot and the other showAgain. Prepare for bad code-
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *defaults1 = [NSUserDefaults standardUserDefaults]; //Here is where it is supposed to be loading the firstBoot variable to check whether or not it is the first boot
NSInteger boot = [defaults1 integerForKey:#"firstBoot"];
firstBoot = boot; //Sort of pointless variable swapping
if (firstBoot == 0) //Detects if isn't first boot, checks whether or not showAgain is yes or no (1=yes, 0=no)
{
NSUserDefaults *defaults1 = [NSUserDefaults standardUserDefaults];
NSInteger boot = [defaults1 integerForKey:#"firstBoot"];
NSUserDefaults *defaults2 = [NSUserDefaults standardUserDefaults];
NSInteger show = [defaults2 integerForKey:#"showAgain"];
firstBoot = boot; //More var swapping
showAgain = show; //^^
}
else
{
firstBoot = 1; //If it is the first boot, or the variable wasn't 0, it sets them both to 1.
showAgain = 1;
}
if ((firstBoot == 1) || (showAgain == 1)) //Checks if its the firstBoot or showAgain is set to yes
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Check the 'About' tab for help!" //Displays alert
message:#""
delegate:self
cancelButtonTitle:#"Don't show again"
otherButtonTitles:#"OK", nil];
[alert show];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"firstboot and showagain != 1" //Displays alert if it isn't the first boot, or isn't 1 and showAgain isn't set to yes(1).
message:#""
delegate:self
cancelButtonTitle:#"wrong"
otherButtonTitles:#"OK", nil];
[alert show];
}
}
Alert-
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == [alertView cancelButtonIndex])
{
showAgain = 0; //If user clicks "Don't show again", set showAgain to off(0) and tell it it isn't the first boot anymore
firstBoot = 0;
NSUserDefaults *defaults1 = [NSUserDefaults standardUserDefaults];
[defaults1 setInteger:0 forKey:#"firstBoot"]; //Hopefully stores firstBoot as 0
[defaults1 synchronize];
NSUserDefaults *defaults2 = [NSUserDefaults standardUserDefaults];
[defaults2 setInteger:0 forKey:#"showAgain"]; //Again storing showAgain as 0
[defaults2 synchronize];
}
}
The first alert should pop up the very first time you run the app, while the second one is a debugger placeholder, and should run every time after the first time. For me, the second one is running first, telling me that firstBoot and showAgain != 1.
NSInteger boot = [defaults1 integerForKey:#"firstBoot"]; will return 0 until you have saved a value in your defaults. 0, NO or nil are returned for keys that don't have any values stored.
The correct way to handle this is to register default values before you try to retrieve these user defaults.
// register default values. until you save your own value "firstBoot" will return YES
// you should put these two lines in the `application:didFinishLaunchingWithOptions:`
// method of the AppDelegate. Add all userdefaults that should have default values there
NSDictionary *defaultUserDefaults = #{ #"firstBoot" : #YES };
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultUserDefaults];
// use BOOL instead of integer
BOOL firstBoot = [[NSUserDefaults standardUserDefaults] boolForKey:#"firstBoot"];
if (firstBoot) {
NSLog(#"first launch");
[[NSUserDefaults standardUserDefaults] setBool:NO forKey:#"firstBoot"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
else {
NSLog(#"has been launched before");
}
How would firstBoot be set to YES on the first boot? Who would have set it?
Call registerDefaults: at the start of the application for all properties that should have values different from 0 before they have been explicitely set. For example, with a key firstBoot = YES. Alternatively, use a property "notFirstBoot" where the return value for missing properties ("NO") is what you actually want.
And there is really no need to call standardUserDefaults again and again.
Related
1.Whatever I do the saveButton method won't save and it still returns 0 for REJECTIONS
2.Please help me fix my saveButton to userdefaults method
3.I've tried multiple things and the values still won't change
#import "CCViewController.h"
#interface CCViewController ()
#end
#implementation CCViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// [NSUserDefaults integerForKey:#"REJECTIONS"];
self.rejectLabel.text=REJECTIONS;
self.acceptedLabel.text=ACCEPTED;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.customInputTextField resignFirstResponder];
}
- (IBAction)resetButton:(UIButton *)sender {
self.rejectLabel.text=#"0";
self.acceptedLabel.text=#"0";
}
- (IBAction)rejectButton:(UIButton *)sender {
int current=stringToInt(self.rejectLabel.text);
int test=stringToInt(self.customInputTextField.text);
if (test>0) {
self.rejectLabel.text=self.customInputTextField.text;
self.customInputTextField.text=nil;
} else {
current++;
self.rejectLabel.text=intToString(current);
}
if (stringToInt(self.rejectLabel.text)==3000) {
UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Achievement Message" message:#"You have reached 3000 rejections!" delegate:nil cancelButtonTitle:#"Close" otherButtonTitles: nil];
[alertView show];
}
}
NSInteger stringToInt(NSString *string) {
return [string integerValue];
}
NSString* intToString(NSInteger integer) {
return [NSString stringWithFormat:#"%d", integer];
}
- (IBAction)acceptedButton:(UIButton *)sender {
int current=stringToInt(self.acceptedLabel.text);
int test=stringToInt(self.customInputTextField.text);
if (test>0) {
self.acceptedLabel.text=self.customInputTextField.text;
self.customInputTextField.text=nil;
} else {
current++;
self.acceptedLabel.text=intToString(current);
}
NSLog(#"after is: %i", current);
}
- (IBAction)unrejectButton:(UIButton *)sender {
int current=stringToInt(self.rejectLabel.text);
current--;
if (current>=0) {
self.rejectLabel.text=intToString(current);
} else {UIAlertView *alertView=[[UIAlertView alloc]initWithTitle:#"Error Message" message:#"You can not have negative rejections!" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];}
NSLog(#"after is: %i", current);
}
- (IBAction)saveButton:(UIButton *)sender {
NSString *rejected=self.rejectLabel.text;
int reject=intToString(self.rejectLabel.text);
NSString *accepted=self.acceptedLabel.text;
NSUserDefaults *rejectTry=[NSUserDefaults standardUserDefaults];
[rejectTry setObject:self.rejectLabel.text forKey:REJECTIONS];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:self.rejectLabel.text forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setValue:#"reject" forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setValue:self.rejectLabel.text forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setObject:#"accepted" forKey:ACCEPTED];
}
NSLog(#"test save %# & %# & %# & %#", REJECTIONS, ACCEPTED, self.rejectLabel.text, self.acceptedLabel.text);
[rejectTry synchronize];
NSLog(#"test save %# & %# & %# & %#, &a %i", REJECTIONS, ACCEPTED, self.rejectLabel.text, self.acceptedLabel.text, picker_value);
}
- (IBAction)loadButton:(id)sender {
self.rejectLabel.text=REJECTIONS;
self.acceptedLabel.text=ACCEPTED;
}
#end
Still not saving to the keys rejections and accepted
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:self.rejectLabel.text forKey:REJECTIONS];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:self.acceptedLabel.text forKey:ACCEPTED];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"test save %# & %# & %# & %# pointers %# %#", REJECTIONS, ACCEPTED, self.rejectLabel.text, self.acceptedLabel.text, defaults, prefs);
It looks like you have muddled up your pointers. You have two references to the same instance of userDefaults yet you expect different results when writing to each one. Here, lets walk through your code
NSString *rejected=self.rejectLabel.text;
int reject=intToString(self.rejectLabel.text);
NSString *accepted=self.acceptedLabel.text;
NSUserDefaults *rejectTry=[NSUserDefaults standardUserDefaults];
Lets stop here. standardUserDefaults is a singleton object. You are not creating a user defaults object when you call this method. You then go on to set a value
[rejectTry setObject:self.rejectLabel.text forKey:REJECTIONS];
This works fine.
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:self.rejectLabel.text forKey:REJECTIONS];
Now you have written over your previous value!
[[NSUserDefaults standardUserDefaults] setValue:#"reject" forKey:REJECTIONS];
And you do it again!
[[NSUserDefaults standardUserDefaults] setValue:self.rejectLabel.text forKey:REJECTIONS];
[[NSUserDefaults standardUserDefaults] setObject:#"accepted" forKey:ACCEPTED];
Conclusion
What you should be doing is creating a local variable like this NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; Then use this for all your writes. Then you will see how you are overwriting the value with key REJECTIONS multiple times
hi i am trying to store my username and password in my app with NSUserdefaults and checkbox.
my code is ..
In viewdidload
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:UserText.text forKey:#"infoString"];
[defaults setObject:PasswdText.text forKey:#"infoString1"];
[defaults synchronize];
UserText.text=[[NSUserDefaults standardUserDefaults] objectForKey:#"infoString"];
and
- (IBAction)checkButton:(id)sender {
if (!checked) {
[checkBoxButton setImage:[UIImage imageNamed:#"checkbox_ticked.png"] forState:UIControlStateNormal];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.UserText.text=[defaults objectForKey:#"infoString"];
self.PasswdText.text = [defaults objectForKey:#"infoString1"];
checked = YES;
}
else if (checked) {
[checkBoxButton setImage:[UIImage imageNamed:#"checkbox_not_ticked.png"] forState:UIControlStateNormal];
checked = NO;
}
}
and my result is if i click checkbox means my textfield is refreshed.where i made mistake?
thanks in advance.
You should save the values in NSUserDefaults when User Performed Submit action, Like this
- (void)submitButtontapped {
if (checked) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:UserText.text forKey:#"infoString"];
[defaults setObject:PasswdText.text forKey:#"infoString1"];
[defaults synchronize];
UserText.text=[[NSUserDefaults standardUserDefaults] objectForKey:#"infoString"];
}
// do the next thing
}
- (IBAction)checkButton:(id)sender {
if (checked) {
checked = NO;
[checkBoxButton setImage:[UIImage imageNamed:#"checkbox_not_ticked.png"] forState:UIControlStateNormal];
} else {
checked = YES;
[checkBoxButton setImage:[UIImage imageNamed:#"checkbox_ticked.png"] forState:UIControlStateNormal];
}
}
I'm trying to Update a Dictionary, saved in the UserDefaults.
However, it just doesn't want to update the Object at the given Index. I have no idea why. The Object with it's values stay the same.
Code:
- (void) saveUser
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *users = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:#"users"]];
BOOL userAlreadyAdded = FALSE;
NSUInteger count = 0;
for (NSMutableDictionary *user in users) {
if ([[user objectForKey:#"username"] isEqualToString:[defaults objectForKey:#"username"]]) {
NSLog(#"User found: %#", user);
[user setObject:sid forKey:#"sess"];
[user setObject:mid forKey:#"seca"];
[users replaceObjectAtIndex:count withObject:user];
userAlreadyAdded = TRUE;
}
count++;
}
if (!userAlreadyAdded) {
NSMutableDictionary *userToAdd = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[defaults objectForKey:#"username"], #"username",
sid, #"sess",
mid, #"seca",
nil];
[users addObject:userToAdd];
}
NSLog(#"USERS TO SAVE: %#", users);
[defaults setObject:users forKey:#"users"];
[defaults synchronize];
}
Values returned from NSUserDefaults are immutable, even if you set a
mutable object as the value. For example, if you set a mutable string
as the value for "MyStringDefault", the string you later retrieve
using stringForKey: will be immutable.
try removing the object and adding it again.
For each user create a Mutable Dictionary from the one you have like you already did with 'users' (initWithArray).
NSMutableDictionary* mutableUser = [NSMutableDictionary dictionaryWithDictionary:user];
Also I'm not entirely sure you're safe to presume that the object at index of your count is the object you expect because the for in loop enumerates differently. I would use setObjectForKey, not replaceAtIndex.
I'm working on my app but i need some help.
I need a 'php-like session' in Objective C (without using connection to the internet)
I've thought about global vars, but my app seems to reset them when reloading the view.
This is my current code
SecondViewController.h
#interface SecondViewController : UIViewController
{
NSString * string;
}
SecondViewController.m
#interface SecondViewController ()
#end
#implementation SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (! [string isEqualToString:#"Hello"])
{
NSLog(#"Hello");
string = #"Hello";
}
else
{
NSLog(#"Bye");
}
}
#end
But everytime I reload SecondViewController the 'string' is reseted to its default value.
I'm looking for something that we use in php (a.e. $_SESSION['string'] = 'hello')
It could be helpful to you . It stores the values until unless delete the app from your device .
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// saving an NSString
[prefs setObject:#"TextToSave" forKey:#"keyToLookupString"];
// saving an NSInteger
[prefs setInteger:42 forKey:#"integerKey"];
// saving a Double
[prefs setDouble:3.1415 forKey:#"doubleKey"];
// saving a Float
[prefs setFloat:1.2345678 forKey:#"floatKey"];
// This is suggested to synch prefs, but is not needed (I didn't put it in my tut)
[prefs synchronize];
**Retrieving**
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
// getting an NSString
NSString *myString = [prefs stringForKey:#"keyToLookupString"];
// getting an NSInteger
NSInteger myInt = [prefs integerForKey:#"integerKey"];
// getting an Float
float myFloat = [prefs floatForKey:#"floatKey"];
I am moving images around in my app which is working fine. The problem is that I'd like to keep the images in place when the user comes back to that view. At present, I am using a string to hold the image centre:
NSString *centre = NSStringFromCGPoint(image.center);
I have an NSUserDefault variable called theCentre:
theCentre = [NSUserDefaults standardUserDefaults];
which I try to save using:
[theCentre setObject:centre forKey:#"centre"];
When I output the log, I get the following:
{280, 320}
which is great.
In the viewDidLoad, I have tried the exact same log and it is returning (null). I take it that this means it isn't saving theCentre properly. Am I missing something fundamental here because I have used NSUserDefaults elsewhere in my app and it has been working ok. Many thanks in advance.
Edit: this is the whole code to try and aid debugging :)
-(void)getBounds
{
lowerBoundX = 250;
upperBoundX = 310;
lowerBoundY = 290;
upperBoundY = 350;
}
#pragma mark -
#pragma mark UIPanGestureRecognizer selector
- (void) dragGesture:(UIPanGestureRecognizer *) panGesture
{
[self getBounds];
CGPoint translation = [panGesture translationInView:self.view];
switch (panGesture.state) {
case UIGestureRecognizerStateBegan:{
originalCentre = dragImage.center;
}
break;
case UIGestureRecognizerStateChanged:{
dragImage.center = CGPointMake(dragImage.center.x + translation.x,
dragImage.center.y + translation.y);
}
break;
case UIGestureRecognizerStateEnded:{
if (((dragImage.center.x >= lowerBoundX) && (dragImage.center.y >= lowerBoundY) &&
(dragImage.center.x <= upperBoundX) && (dragImage.center.y <= upperBoundY))) {
dragImage.center = CGPointMake(280, 320);
[dragImage setUserInteractionEnabled:NO];
theCentre = [NSUserDefaults standardUserDefaults];
NSString *centre = NSStringFromCGPoint(dragImage.center);
[theCentre setObject:centre forKey:#"centre"];
NSLog(#"%#", [theCentre objectForKey:#"centre"]);
[theCentre synchronize];
break;
}
[UIView animateWithDuration:0.5
animations:^{
dragImage.center = originalCentre;
}
completion:^(BOOL finished){
}];
}
break;
default:
break;
}
[panGesture setTranslation:CGPointZero inView:self.view];
}
-(IBAction)clear{
[UIImageView animateWithDuration:0.5 animations:^{
dragImage.center = CGPointMake(100, 200);
}];
[dragImage setUserInteractionEnabled:YES];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"%#", [theCentre objectForKey:#"centre"]);
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragGesture:)];
[dragImage addGestureRecognizer:panGesture];
[dragImage setUserInteractionEnabled:YES];
}
Data saved in NSUserDefaults is first cached and thus it is not available instantly from other instances of the NSUserDefaults. The data is saved periodically on some predefined events/time intervals. However you can force a data synchronization by calling synchronize like this:
NSString *theCenter = NSStringFromCGPoint(image.center);
theCenter = [NSUserDefaults standardUserDefaults];
[theCenter setObject:centre forKey:#"center"];
[theCenter synchronize];