Problems with saving an int in NSUserDefaults iOS - ios

I am using the below code to save an int and some other stuff into NSUserDefaults from my AppDelegate. The other array that I'm saving is full of objects that conform to NSCoding, so I don't think that that's an issue. If the current place is not zero, then that means that there is a session in progress, so all the data is loaded. When saving my data, it only saves if the current place is not zero which indicates that there is a session in progress. I know this calls when I exit the app on my physical device because the NSLog message appears in the debugger.
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
if (self.currentPlace != 0) {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = self.places; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:#"places"];
[defaults setInteger:self.currentPlace forKey:#"current"];
NSLog(#"Saving and Quitting b/c we have a place verified!");
[defaults synchronize];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [defaults integerForKey:#"current"];
self.currentPlace = (int)myInt;
if (self.currentPlace != 0) {
NSData *data = [defaults objectForKey:#"places"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
self.places = [arr mutableCopy];
NSLog(#"Current Place: %i",self.currentPlace);
}
}
I am using my AppDelegate to store data that can be accessed from multiple screens in my app. In the first ViewController, the user is presented with a menu. If the appDelegate's currnentPlace value is not 0, then the option to continue with the loaded data from the AppDelegate is presented. However, this option is never presented. I check the currentPlace int's value using the following in my first view controller:
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// Do any additional setup after loading the view, typically from a nib.
[self setupViews];
self.spinner.alpha = 0;
NSLog(#"Current %i",delegate.currentPlace);
if (delegate.currentPlace == 0) {
self.continueButton.enabled = false;
self.continueButton.alpha = 0.5;
}
else if (delegate.currentPlace != 0) {
self.continueButton.enabled = true;
self.continueButton.alpha = 1;
}
If anyone could see what I'm doing wrong it would be greatly appreciated.

Move your data restoration code block into a method, as below:
- (void)restoreData {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [defaults integerForKey:#"current"];
self.currentPlace = (int)myInt;
if (self.currentPlace != 0) {
NSData *data = [defaults objectForKey:#"places"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];
self.places = [arr mutableCopy];
NSLog(#"Current Place: %i",self.currentPlace);
}
}
Then call this method in application:didFinishLaunchingWithOptions: and applicationWillEnterForeground: methods in AppDelegate.

You need to use
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
in you controller in which you are making the object of AppDelegate class.
If still you are not able to get current value then just store the value in user default as a string and when you acess it, convert it in appropriate data type which you want. Might be this could help you.

Related

Saving a user/account to be stored and passed around app

I am using AFNetworking 2.0 and Mantle in order to connect to an API and return a user account.
My plan is to call the function that gets the user data in the application:didFinishLaunchingWithOptions: method. I will then encode the data and save the user into NSUserDefaults
Is this the best way to approach this task? What alternatives are there? (I'd like to stay away from creating singletons)
UPDATE
Some code to maybe help show what I am thinking in my head:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedUserData = [defaults objectForKey:#"currentUser"];
if (encodedUserData) {
self.currentUser = [NSKeyedUnarchiver unarchiveObjectWithData:encodedUserData];
} else {
NSLog(#"No current user");
// Show login ViewController
}
If you are going to get the user account every time user launches the app, then you don't need to store it in NSUserDefaults. Just use a singleton or static object to store it as your model object type.
static Account *_userAccount = nil;
+ (Account*)userAccount {
return _userAccount;
}
+ (void)setUserAccount:(Account*)account {
_userAccount = account;
}
You can use NSUserDefaults for this purpose and can access it through out application.
// to save data in userdefaults
[[NSUserDefaults standardUserDefaults] setObject:#"your object" forKey:#"your key"];
[[NSUserDefaults standardUserDefaults] synchronize];
// for getting saved data from User defaults
NSData *encodedUserData = [[NSUserDefaults standardUserDefaults] objectForKey:#"your key"];
if (encodedUserData) {
self.currentUser = [NSKeyedUnarchiver unarchiveObjectWithData:encodedUserData];
} else {
NSLog(#"No current user");
// Show login ViewController
}

Save and Load Data on Today Extensions (iOS 8)

Is it possible to save and load data on Today Extension using NSUserDefaults?
After closing the Notification Center, the widget behaves like an app which is terminated, so any data results lost. How could I solve this issue?
This is my code:
NSUserDefaults *defaults;
- (void)viewDidLoad {
[super viewDidLoad];
defaults = [NSUserDefaults standardUserDefaults];
NSArray *loadStrings = [defaults stringArrayForKey:#"savedStrings"];
if ([loadStrings objectAtIndex:0] != nil) {
[display setText:[NSString stringWithFormat:#"%#", [loadStrings objectAtIndex:0]]];
}
if ([loadStrings objectAtIndex:1] != nil) {
calculatorMemory = [NSString stringWithFormat:#"%#", [loadStrings objectAtIndex:1]].doubleValue;
}
}
- (IBAction)saveData:(id)sender {
NSString *displayString;
NSString *memoryString;
NSArray *saveStrings = [[NSArray alloc] initWithObjects: displayString, memoryString, nil];
defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:saveStrings forKey:#"savedStrings"];
[defaults synchronize];
}
You need to use app group identifier instead of com.*
For instance:
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.company.appgroup"];
Don't forget to synchronise when you store data
[shared synchronize];
You need to add the App Group stuff detailed under here and then if it actually worked (pretty iffy under beta) it should allow you to share NSUserDefault data like normal between the host and widget.
Edit: Normal NSUserDefaults does not work. Apple has implemented a new method. To use, simply redefine your NSUserDefaults instance like this:
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"com.you.app.container"];
For anyone wondering how in the world do you save and get values then look at this code.
In your regular app add this to save whatever you like in your *.m file.
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.yourcompanyname.TodayExtensionSharingDefaults"];
//save dic
[shared setObject:dictionary2 forKey:#"dicForTodayWidget"];
//save array
[shared setObject:tempArray2 forKey:#"arrayForTodayWidget"];
//save some value
[shared setObject:#"1234" forKey:#"myValForTodayWidget"];
[shared synchronize];
In your today widget under TodayViewController.m in viewDidLoad add this.
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.yourcompanyname.TodayExtensionSharingDefaults"];
//get dic
NSMutableDictionary *dictionary = [shared objectForKey:#"dicForTodayWidget"];
You first need the App Groups set up for both targets (application and the extension).
Then, use the
NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:#"group.company.myapp"];
to obtain the defaults object which you can read from/write to as usual.
If you want to be notified of changes to the defaults, use the NSUserDefaultsDidChangeNotification in your widget (or app).
For a step-by-step tutorial explaining all this, take a look at this blog post.
#edukulele
Today Extension and Main app run on two processes. Today Extension can't receive NSUserDefaultsDidChangeNotifications. I tried use MMWormhole. It is very good.

NSUserDefault not able to retrieve value double

I'm creating a simple double value, saving it as NSUserDefault and trying to recover it...but it doesn't.
- (IBAction)try:(id)sender {
double value = 42.00;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setDouble:value forKey:#"kDoubleKey"];
// NSLog(#"loading %f",myDouble);
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSUserDefaults *fetchDefaults = [NSUserDefaults standardUserDefaults];
double intValue = [fetchDefaults doubleForKey:#"kDoubleKey"];
NSLog(#"douvle retrieve %f",intValue);
}
Do not forget to synchronise whenever you save something to the defaults:
put this at the end of your try method
[[NSUserDefaults standardUserDefaults]synchronize];
Here is what apple says about this: Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.

Attempt to login in CocoaLibSpotify with stored credentials fails

I've integrated CocoaLibSpotify in my iOS app and I am developing user login.
By the first time, the login controller is shown, and if the login is successful, user credentials are generated and stored in NSDefaults, as Rich Able explains in SPLoginViewController to remember credentials:
The code is the next:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *storedCredentials = [defaults valueForKey:#"SpotifyUsers"];
if (storedCredentials == nil)
[self performSelector:#selector(showLogin) withObject:nil afterDelay:0.0];
else
{
NSString *u = [storedCredentials objectForKey:#"LastUser"] ;
[[SPSession sharedSession] attemptLoginWithUserName:u existingCredential: [storedCredentials objectForKey:u]];
}
-(void)session:(SPSession *)aSession didGenerateLoginCredentials:(NSString *)credential forUserName:(NSString *)userName
{
NSLog(#"stored credentials");
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *storedCredentials = [[defaults valueForKey:#"SpotifyUsers"] mutableCopy];
if (storedCredentials == nil)
storedCredentials = [NSMutableDictionary dictionary];
[storedCredentials setValue:credential forKey:userName];
[storedCredentials setValue:userName forKey:#"LastUser"];
[defaults setValue:storedCredentials forKey:#"SpotifyUsers"];
[defaults synchronize];
}
But, when I close the app and restart it again, I attempt to log with the stored credentials, but the login always fails.
Is this possible to achieve or when I restart the app, the session becomes invalid and I need to ask the user to log again?
Thanks in advance!

writing or reading to NSUserDefaults while dismissing viewcontroller crashes with Exc bad access

While dismissing the modalView I save the changes in NSUserDefaultsand synchronize them in the method "saveinUserDeaultsObjects".
Now, repeating this process twice crashes the with exc bad access.(i.e presenting and dismissing).
But, if I dismiss viewcontroller after 1 sec delay using perform selector the app works fine.
What can I infer from this ? - I think writing to NSUserdefaults taking some time while the passed object is released.
If it is the case how to handle such situations ?
- (void)dismissViewController {
[Utils saveinUserDeaultsObjects:self.sortVlaue Forkey:#"SortByValue"];
[Utils saveinUserDeaultsObjects:self.state Forkey:#"State"];
[Utils saveinUserDeaultsObjects:self.topic Forkey:#"AOPString"];
[self dismissViewControllerAnimated:YES completion:^{}];
}
Thank You.
Update
+ (void)saveinUserDeaultsObjects:(NSString )valueObject Forkey:(NSString)key {
//NSLog(#"SaveUseref for key: %# object: %#",key, valueObject);
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
[userPreferences setObject:valueObject forKey:key];
[userPreferences synchronize];
}
Update 2
+ (NSString )retriveFromUserDeaultsStringForkey:(NSString)key {
NSUserDefaults *userPreferences = [NSUserDefaults standardUserDefaults];
NSString *value = nil;
if (userPreferences) value = (NSString *)[userPreferences objectForKey:key];
return value;
}
the crash it ocassionally shows is at reading the "value" object above. Mostly it is EXC bad access and the malloc stack trace is:
12: 0x1c0b85f in -[CFXPreferencesPropertyListSourceSynchronizer createPlistFromDisk]
13: 0x1bdfc56 in -[CFXPreferencesPropertyListSourceSynchronizer synchronizeAlready]

Resources