I have an NSMutableArray inside of my AppDelegate, and I'm attempting to save it to NSUserDefaults. The NSMutableArray (strainsfinal) contains a list of favorited items. I want this list to save, and be present even if the app is shut down, and then restarted. Does anyone know why my code isn't working (not saving my data)? See below:
AppDelegate.m
-(void)updateStrains:(NSDictionary *)item
{
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataSave = [currentDefaults objectForKey:#"strains"];
if (strainsfinal != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataSave];
if (oldSavedArray != nil)
strainsfinal = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
strainsfinal = [[NSMutableArray alloc] init];
}
}
EDIT: Appdelegate.m So I've changed my above method to the method below (and I thought it should work), but the app crashes, saying: "Terminating app due to uncaught exception 'NSInvalidArguementException', reason: 'NSConcreteAttributedString initwithString: nil 'value'.
What am I missing?!
-(void)updateStrains:(NSDictionary *)item {
NSData *dataSave = [NSKeyedArchiver archivedDataWithRootObject:strainsfinal];
[[NSUserDefaults standardUserDefaults] setObject:dataSave forKey:#"strains"];
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc postNotificationName:#"arrayupdated" object:self userInfo:nil];
NSLog(#"updated strains %#",strainsfinal);
}
You must add
[currentDefaults synchronize];
each time after you save something to userDefaults;
But for such kind of data is better to use .plist files.
Check documentation for more info.
EDITED Code:
-(void)updateStrains:(NSDictionary *)item {
NSData *dataSave = [NSKeyedArchiver archivedDataWithRootObject:item[#"strainsfinal"]];
[[NSUserDefaults standardUserDefaults] setObject:dataSave forKey:#"strains"];
// NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
// [nc postNotificationName:#"arrayupdated" object:self userInfo:nil];
NSLog(#"updated strains %#",strainsfinal);
[[NSUserDefaults standardUserDefaults] synchronize]; // this will save you UserDefaults
}
use following method :
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
[userDef setObject:array1 forKey:#"DataArra1"];
[userDef setObject:array2 forKey:#"DataArr2"];
[userDef synchronize];
To retrieve the information:
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
NSArray *arrayText2 = [userDef objectForKey:#"DataArra1"];
NSArray *arrayText1 = [userDef objectForKey:#"DataArr2"];
You should archive NSArray before saving.
[[NSUserDefaults standardUserDefaults]
setObject:[NSKeyedArchiver archivedDataWithRootObject:yourArray]
forKey:#"yourArray"];
and unarchive when getting from NSUserDefaults.
NSData *data = [currentDefaults objectForKey:#"yourArray"];
if (data != nil)
{
NSArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
Related
In my iOS app when I'm logging in I used set UserID and loginstatus into NSUserDefaults like this.
#implementation Login{
NSInteger UserId;
NSUserDefaults *preferences;
}
- (IBAction)LogInClick:(UIButton *)sender {
[preferences setInteger:UserId forKey:#"UserId"]; //UserId=40;
[preferences setBool:YES forKey:#"loginstatus"];
[preferences synchronize];
NSLog(#"All NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
NSString *uID = [preferences stringForKey:#"UserId"];
NSLog(#"UserID: %#",uID);
}
But the values are not setting in the NSUserDefaults. I tried to log all NSUserDefaults value and also the single UserID value but all fields are coming null.
Later I use this code to logout
- (IBAction)LogOutClick:(UIButton *)sender {
[[NSUserDefaults standardUserDefaults] setObject:0 forKey:#"UserId"];
[[NSUserDefaults standardUserDefaults] setObject:NO forKey:#"loginstatus"];
/* [preferences setInteger:0 forKey:#"UserId"];
[preferences setBool:NO forKey:#"loginstatus"];
[preferences synchronize];*/
NSLog(#"All NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
}
First when i logged out it all sets to zero and now the values are not setting. Can anybody tell me what the problem is?
That's because NSUserDefaults *preferences; is just a pointer. And it's value is nil, I presume. You should initialize it. For instance:
- (IBAction)LogInClick:(UIButton *)sender {
preferences = [NSUserDefaults standardUserDefaults];
[preferences setInteger:UserId forKey:#"UserId"]; //UserId=40;
[preferences setBool:YES forKey:#"loginstatus"];
[preferences synchronize];
...
May be a more logical place to initialize preferences would be an init method, or something else that you would consider appropriate for this purpose.
You haven't get the standard userdefaults reference. Change this method
- (IBAction)LogInClick:(UIButton *)sender {
preferences = [NSUserDefaults standardUserDefaults];
[preferences setInteger:UserId forKey:#"UserId"]; //UserId=40;
[preferences setBool:YES forKey:#"loginstatus"];
[preferences synchronize];
NSLog(#"All NSUserDefaults: %#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
NSString *uID = [preferences stringForKey:#"UserId"];
NSLog(#"UserID: %#",uID);
}
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I'm having trouble in create a NSArray class Method with Text Fields strings to use in another views controllers classes.
Let me show you what i have done:
First,in settings view controller, i'm collecting information in 3 text fields and saving with NSUserdefaults:
- (void)viewDidLoad
{
// Get the stored data before the view loads
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *toEmail = [defaults objectForKey:#"toEmail"];
NSString *ccEmail = [defaults objectForKey:#"ccEmail"];
NSString *bccEmail = [defaults objectForKey:#"bccEmail"];
// Update the UI elements with the saved data
self.toEmailTextField.text = toEmail;
self.ccEmailTextField.text = ccEmail;
self.bccEmailTextField.text = bccEmail;
[super viewDidLoad];
[self sideBarButton];
[self dismissTextFields];
}
- (IBAction)toEmailAction:(id)sender {
NSString *toEmail = self.toEmailTextField.text;
// Store the data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:toEmail forKey:#"toEmail"];
[defaults synchronize];
NSLog(#"Data saved");
}
- (IBAction)ccEmailAction:(id)sender {
NSString *ccEmail = self.ccEmailTextField.text;
// Store the data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:ccEmail forKey:#"ccEmail"];
[defaults synchronize];
NSLog(#"Data saved");
}
- (IBAction)bccEmailAction:(id)sender {
NSString *bccEmail = self.bccEmailTextField.text;
// Store the data
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:bccEmail forKey:#"bccEmail"];
[defaults synchronize];
NSLog(#"Data saved");
}
Second I have another view controller with email API where I need to use the strings save with NSUserdefault in the settings view controller.(marked as text 1, text 2, and text 3)
#pragma mark - Email
- (IBAction)showEmail:(id)sender {
// Email Subject
NSString *emailTitle = #"GliLog Email";
// Email Content
NSString *messageBody = #"GliLog Email Test!!!";
// To address
NSArray *toRecipent = [NSArray arrayWithObject:#"text 1"];
NSArray *ccRecipient = [NSArray arrayWithObject:#"text 2"];
NSArray *bccRecipient = [NSArray arrayWithObject:#"text 3"];
MFMailComposeViewController *mc = [[MFMailComposeViewController alloc] init];
mc.mailComposeDelegate = self;
[mc setSubject:emailTitle];
[mc setMessageBody:messageBody isHTML:NO];
[mc setToRecipients:toRecipent];
[mc setCcRecipients:ccRecipient];
[mc setBccRecipients:bccRecipient];
// Present mail view controller on screen
[self presentViewController:mc animated:YES completion:NULL];
}
- (void) mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
switch (result)
{
case MFMailComposeResultCancelled:
NSLog(#"Mail cancelled");
break;
case MFMailComposeResultSaved:
NSLog(#"Mail saved");
break;
case MFMailComposeResultSent:
NSLog(#"Mail sent");
break;
case MFMailComposeResultFailed:
NSLog(#"Mail sent failure: %#", [error localizedDescription]);
break;
default:
break;
}
// Close the Mail Interface
[self dismissViewControllerAnimated:YES completion:NULL];
}
How can i "pass" the strings from settings view controller to another view.
Best regards
You already have the answer in your first view, when reading the NSUserDefaults and storing to the strings:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *toEmail = [defaults objectForKey:#"toEmail"];
NSString *ccEmail = [defaults objectForKey:#"ccEmail"];
NSString *bccEmail = [defaults objectForKey:#"bccEmail"];
Just apply the same thing in second view controller,
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *toRecipent = [NSArray arrayWithObject:[defaults objectForKey:#"toEmail"]];
NSArray *ccRecipient = [NSArray arrayWithObject:[defaults objectForKey:#"ccEmail"]];
NSArray *bccRecipient = [NSArray arrayWithObject:[defaults objectForKey:#"bccEmail"]];
if you are storing the data in the NSUserDefaults, just get the value from it.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString * toEmail = [defaults objectForKey:#"toEmail"];
NSString * ccEmail = [defaults objectForKey:#"ccEmail"];
A nice and simple tutorial about NSUserDefaults
I am saving Textfield text using NSUserDefaults on button click in ViewController2
My code is
ButtonClick()
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
[userDefaults synchronize];
}
Then ViewDidLoad method i am Retrieving like this
-(void)viewDidLoad
{
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[keyWordArray addObject:[userDefaults objectForKey:#"Keywords"]];
[userDefaults synchronize];
}
Here i am assigning this keyWordArray to tableview
like cell.textlabel.text =[keyWordArray objectAtIndex:indexPath.row];
First i entered text(First) in textfield and click button it is showing in table like
First
Second time i entered text (second) in textfield and click button it is showing table like
First
Second
Here everything working fine. The problem is when i come to viewController2 from ViewController1. It is showing last entered value only
like
Second
what going wrong here?
Try This
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
[selt.tableView reload]; //reload the table every time a new text is added
}
-(void)viewDidLoad {
if([[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"]==nil){
keyWordArray = [[NSMutableArray alloc] init];
}
else{
keyWordArray = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
}
}
Try this,
- (IBAction)buttonclick:(id)sender {
[keyWordArray addObject:keyWordField.text];
NSUserDefaults *userDefaults =[NSUserDefaults standardUserDefaults];
[userDefaults setObject:keyWordArray forKey:#"Keywords"];
[userDefaults synchronize];
}
and
-(void)viewDidLoad
{
NSArray *array = [[NSUserDefaults standardUserDefaults] objectForKey:#"Keywords"];
if (!array) {
keyWordArray = [[NSMutableArray alloc] init];
} else {
keyWordArray = [NSMutableArray arrayWithArray:nameArray];
}
}
Since you are overriding your
[userDefaults setObject:keyWordField.text forKey:#"Keywords"];
every then and there your every object in the array will be referring to your [userDefaults setObject:keyWordField.text forKey:#"Keywords"]; object thats y the problem comes
Because if you are navigate to another viewController. since the your user default value save in second only.
After pop to back through viewDidLoad is loaded. so far its have second string only save in User Default.
that way it display second only.
You code is overwrite the last value and remove previous values from NSUserDefault. You have to use array to stored all value and you have save array into NSUserDefault.
NSMutableArray *aryDataDefault = [[NSUserDefaults standardUserDefaults] valueForKey:#"YourKey"];
[aryDataDefault addObject:textfield.text];
[[NSUserDefaults standardUserDefaults] setObject:aryDataDefault forKey:#"YourKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
I am working with the simulator, and I am doing something like this when the app starts to check if it was opened for the first time:
and then checking if that key/value is empty so that this code executes only once:
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if([standardUserDefaults objectForKey:#"first_time_cookie"] == nil)
{
[standardUserDefaults setBool:YES forKey:#"first_time_cookie"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
but every time I run the program, it executes again. Any idea what is going wrong here?
Just a guess: standardUserDefaults is nil?
You can do different!
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], #"first_time_cookie"];
[defaults registerDefaults:dict];
if ([defaults boolForKey:#"first_time_cookie"] == NO){
[defaults setBool:YES forKey:#"first_time_cookie"];
[defaults synchronize];
}
a bool is not an object. This should work
if([standardUserDefaults boolForKey:#"first_time_cookie"] == NO)
{
[standardUserDefaults setBool:YES forKey:#"first_time_cookie"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
try using
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"first_time_cookie"] == false)
and let me know if it works,
gung-ho
I use NSNotification to send notification when switch is changed position to start updating annotations on map. My problem is that I have 8 switches and when user change position of few switches, map updates for many times. How a limit that to just one notification?
- (IBAction)saveSwitch:(id)sender
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyAppSettingsChanged" object:self userInfo:nil];
NSUserDefaults *defs1 = [NSUserDefaults standardUserDefaults];
[defs1 setBool: blackSwitch.on forKey: #"blackKey"];
NSUserDefaults *defs2 = [NSUserDefaults standardUserDefaults];
[defs2 setBool: greenSwitch.on forKey: #"greenKey"];
NSUserDefaults *defs3 = [NSUserDefaults standardUserDefaults];
[defs3 setBool: purpleSwitch.on forKey: #"purpleKey"];
NSUserDefaults *defs4 = [NSUserDefaults standardUserDefaults];
[defs4 setBool: orangeSwitch.on forKey: #"orangeKey"];
NSUserDefaults *defs5 = [NSUserDefaults standardUserDefaults];
[defs5 setBool: blueSwitch.on forKey: #"blueKey"];
NSUserDefaults *defs6 = [NSUserDefaults standardUserDefaults];
[defs6 setBool: redSwitch.on forKey: #"redKey"];
NSUserDefaults *defs7 = [NSUserDefaults standardUserDefaults];
[defs7 setBool: darkblueSwitch.on forKey: #"darkblueKey"];
NSUserDefaults *defs8 = [NSUserDefaults standardUserDefaults];
[defs8 setBool: yellowSwitch.on forKey: #"yellowKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
In another view
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(onAppSettingsChanged:) name:#"MyAppSettingsChanged" object:nil];
}
Updating annotations
- (void) onAppSettingsChanged:(NSNotification *)notification {
NSLog(#"Settings was changed");
//Create the thread
[NSThread detachNewThreadSelector:#selector(loadPList) toTarget:self withObject:nil];
}
You must update some BOOLean value to indicate that you are not currently processing an update, and proceed accordingly. I.E.
- (void) onAppSettingsChanged:(NSNotification *)notification {
NSLog(#"Settings was changed");
if (!myBoolToIndicateProcessing) {
//Create the thread
myBoolToIndicateProcessing = YES;
[NSThread detachNewThreadSelector:#selector(loadPList) toTarget:self withObject:nil];
}
}
Then, when the reload has finished, set the BOOL back to NO.