iOS: Saving a double picker's settings (data persistence) - ios

So I have a double picker where the user sets each wheel to what they want, and then press a button which will display their choice. Easy clean and simple, but I want to store that data for later so that it does not disappear after they close the app and re-open it again. Now, I know how to do it with a datePicker, but not a doublePicker. So my question is how do I tweak my code from saving and retrieving a datePickers info into a doublePicker?
Here is my code for the datePicker:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// Pulling the date out of my picker
NSDate *selectedDate = [self.datePicker date];
[defaults setObject:selectedDate forKey:#"DatePickerViewController.selectedDate"];
And then retrieving it again:
- (void)viewDidLoad
{
[super viewDidLoad];
// Get the date. I'm going to use a little shorthand instead of creating
// a variable for the instance of `NSUserDefaults`.
NSDate *storedDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"DatePickerViewController.selectedDate"];
// Setting the date on the date picker. I'm passing `NO` to `animated:`
// because I'm performing this before the view is on screen, but after
// it has been loaded.
[self.datePicker setDate:storedDate animated:NO];
}
Any help would be appreciated, thx :)

In your UIPickerViewDelegate:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:row forKey:[NSString stringWithFormat:#"DoublePickerViewController.%i", component]];
}
To get the data out:
for (int i = 0; i < doublePicker.numberOfComponents; i++) {
NSInteger *storedInteger = [[NSUserDefaults standardUserDefaults] integerForKey:[NSString stringWithFormat:#"DoublePickerViewController.%i", i];
[doublePicker selectRow:storedInteger inComponent:i animated:NO];
}
For storing multiple values:
In your UIPickerViewDelegate:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *oldArray = [defaults arrayForKey:[NSString stringWithFormat:#"DoublePickerViewController.%i", component]];
//Make a mutable version so we can change it
NSMutableArray *newArray = [oldArray mutableCopy];
if (!newArray) {
newArray = [NSMutableArray array];
}
//Add The Latest Row To The end of the array. We wrap it in an NSNumber so it can be in an array
[newArray addObject:[NSNumber numberWithInteger:row]];
//If you want to have a limit on the amount of values that can be stored then use this
int maxValues = 5;
if (newArray.count >= maxValues) {
//Remove the oldest object
[newArray removeObjectAtIndex:0];
}
[defaults setObject:newArray forKey:[NSString stringWithFormat:#"DoublePickerViewController.%i", component]];
}
To get the data out:
for (int i = 0; i < doublePicker.numberOfComponents; i++) {
NSArray *storedIntegers = [[NSUserDefaults standardUserDefaults] arrayForKey: [NSString stringWithFormat:#"DoublePickerViewController.%i", i];
//I don't know what values you want, but to get an int out of the array:
//int integer = [(NSNumber *)[storedIntegers objectAtIndex:0] intValue];
//And to set the row for a component:
//[doublePicker selectRow:storedInteger inComponent:i animated:NO];
}

Related

Obj C - NSUserDefaults won't give back values to calculate, after loading the view

I am stuck with little problem. I have basic calculating app.
Viewcontroller.m
#import "ViewController.h"
#interface ViewController () <UITextFieldDelegate, UIAlertViewDelegate>
#end
#implementation ViewController
-(void)textFieldDidEndEditing:(UITextField *)textField
{
self.currentSettings = _currentSettings;
[self calculateThePrice];
}
-(void)calculateThePrice
{
float wynik = self.currentSettings.kwh * self.currentSettings.price;
self.priceLabel.text = [NSString stringWithFormat:#"%.02f %#", wynik , self.currentSettings.currency];
}
SettingsVC.m
#import "SettingsVC.h"
#interface SettingsVC () <UITextFieldDelegate>
#end
#implementation SettingsVC
#pragma mark - UserDefaults Implementation
-(void)viewWillAppear:(BOOL)animated
{
[self createCurrencyArray];
NSUserDefaults *priceDef = [NSUserDefaults standardUserDefaults];
NSString *priceDefText = [priceDef stringForKey:#"priceCall"];
_priceTextField.text = priceDefText;
NSUserDefaults *currencyDef = [NSUserDefaults standardUserDefaults];
[_currencyPicker selectRow:[currencyDef integerForKey:#"currencyCall"]
inComponent:0 animated:NO];
[priceDef synchronize];
[currencyDef synchronize];
}
-(void)viewWillDisappear:(BOOL)animated
{
NSString *textOfPriceTexField = _priceTextField.text;
[[NSUserDefaults standardUserDefaults] setObject:textOfPriceTexField forKey:#"priceCall"];
}
Now, the problem is when I want program to automatically-calculate, it won't. To have any result, I have to switch to Second View, choose a value from picker and then when I will go back, I have my result.
But...
- When I change value on 1st screen, result won't change. When I change value on 2nd scree, result won't change. But when I change value on PickerView - TADAH - result updates!
When I go to second view, and go back to first, then go again to second and go back to first, my result changes to "0.00 (NULL)"...
Any ideas where I did wrong? I think it is about NSUserDefaults, I tried many options, nothing worked, nor changed anything.
You need to synchronize NSUserDefaults when you set new values. You are using synchronize when you retrieve values.
Here you don't need 2 pointers to defaults and don't need synchronize:
NSUserDefaults *priceDef = [NSUserDefaults standardUserDefaults];
NSString *priceDefText = [priceDef stringForKey:#"priceCall"];
_priceTextField.text = priceDefText;
[_currencyPicker selectRow:[priceDef integerForKey:#"currencyCall"] inComponent:0 animated:NO];
Here you need synchronizes:
-(void)viewWillDisappear:(BOOL)animated
{
NSString *textOfPriceTexField = _priceTextField.text;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:textOfPriceTexField forKey:#"priceCall"];
[defaults synchronize];
}
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSInteger selectedRow = [_currencyPicker selectedRowInComponent:0];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:selectedRow forKey:#"currencyCall"];
[defaults synchronize];
self.currentSettings.currency = [self.currencyArray objectAtIndex:row];
self.currentSettings.price = [self.priceTextField.text floatValue];
//[self userDidFinishSetting];
}
Try this code
-(void)viewWillDisappear:(BOOL)animated
{
NSString *textOfPriceTexField = _priceTextField.text;
[[NSUserDefaults standardUserDefaults] setObject:textOfPriceTexField forKey:#"priceCall"];
}
-(void)viewWillAppear:(BOOL)animated
{
[self createCurrencyArray];
NSUserDefaults *priceDef = [NSUserDefaults standardUserDefaults];
NSString *priceDefText = [priceDef objectForKey:#"priceCall"];
}
instead of stringForKey you can call objectForKey same as for integerForKey also you can call objectForKey. Actually you are setting the object not string or integer.

Save and load NSMutableArray - NSUserDefaults

I am trying to save a NSMutableArray to NSUserDefaults then reload it and use it to populate the button labels. Can someone please take a look and tell me what i am doing wrong here?
When I am loading the file to new array it appears empty. All of the buttons I am trying to set the titles to are in ibCollectionOutlet called buttons
-(void)save {
[[NSUserDefaults standardUserDefaults] setObject:self.pressCountArray forKey:#"savedFile"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
-(void)load{
NSMutableArray *countArray = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"savedFile"] mutableCopy];
for (NSInteger i = 0; i < [self.pressCountArray count]; i++){
self.pressCountArray[i] = countArray[i];
}
for (NSInteger i = 0; i < [self.buttons count]; i++){
UIButton *btn = self.buttons[i];
int curCnt = [[self.pressCountArray objectAtIndex:i] integerValue];
[btn setTitle:[NSString stringWithFormat:#"%i",curCnt] forState:UIControlStateNormal];
}
}
I think your array contains custom objects.
If that is the case then you should implement NSCoding protocol (for serialization and de-serialization) in your custom model class.
Implement the following NSCoding protocol methods in your class:
- (void)encodeWithCoder:(NSCoder *)encoder;
- (id)initWithCoder:(NSCoder *)decoder;
After that save the data like:
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:self.pressCountArray];
[[NSUserDefaults standardUserDefaults] setObject:encodedObject forKey:[NSString stringWithFormat:#"savedFile"]];
And retrieve the data like:
NSData *encodedObject = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"savedFile"]];
self.pressCountArray = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
It looks like you are not allocating self.pressCountArray during the load and are probably attempting to populate an empty array (in a fairly strange way). Instead simply do:
-(void)load{
self.pressCountArray = [[[NSUserDefaults standardUserDefaults] arrayForKey:#"savedFile"] mutableCopy];
NSAssert([self.pressCountArray count] == [self.buttons count], #"Array count mismatch");
for (NSInteger i = 0; i < [self.buttons count]; i++){
UIButton *btn = self.buttons[i];
int curCnt = [[self.pressCountArray objectAtIndex:i] integerValue];
[btn setTitle:[NSString stringWithFormat:#"%i",curCnt] forState:UIControlStateNormal];
}
}
Note that you need to check that the correct number of array elements have been loaded. I've used an NSAssert in the above code, but you probably need to return NO given it's probably something that can happen in production.

NSUserDefaults can't update a nsmutable array

I saved a nsmutableArray inside a NSUserDefaults.
In the following case, it seems that all the elements from the array are equal to 0, even though in this case position 1 and position 5 should have 1 instead of 0 as a value. I know that NSUserDefaults elements are immutable but ...I did add that mutableCopy when retrieving the value.
Where am I wrong?
//create array
NSMutableArray *objArray = [[NSMutableArray alloc] init];
for (int i=0; i< 100;i++) [objArray addObject:#"0"];
[objArray replaceObjectAtIndex:1 withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
// update
elementPosition = 5;
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
//check the array
NSMutableArray *objArray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:nameFile]];
BOOL displayContent = true;
for (int i=0; i<[objArray count];i++)
{
if ([[objArray objectAtIndex:i] isEqualToString:#"0"])
{
displayContent = false;
}
}
I think when you retrieve and your mutable array from UserDefault and updated but you didn't set that new updated object to UserDefault, its having the old object which was set before. you have to store your update array again to userdefault with same key which update your UserDefautlt.
elementPosition = 5;
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
You should call the synchronize method
[[NSUserDefaults standardUserDefaults] synchronize];
I think you should fix your code follow my bellow code:
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
[[NSUserDefaults standardUserDefaults] synchronize];
...
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:nameFile];
[[NSUserDefaults standardUserDefaults] synchronize];
Replace your code with this:
//create array
NSMutableArray *objArray = [[NSMutableArray alloc] init];
for (int i=0; i< 100;i++){
[objArray addObject:#"0"];
}
[objArray replaceObjectAtIndex:1 withObject:#"1"];
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
//First mistake. Missing this. Without this line the data is not saved in NSUserDefaults
[[NSUserDefaults standardUserDefaults] synchronize];
// update
elementPosition = 5;
NSMutableArray *objArray = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]] mutableCopy];
[objArray replaceObjectAtIndex:elementPosition withObject:#"1"];
//Second Mistake. You did not update the NSUserDefaults again.
[[NSUserDefaults standardUserDefaults] setObject:objArray forKey:name];
[[NSUserDefaults standardUserDefaults] synchronize];
//check the array
NSMutableArray *objArray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:name]];
BOOL displayContent = true;
for (int i=0; i<[objArray count];i++)
{
if ([[objArray objectAtIndex:i] isEqualToString:#"0"])
{
displayContent = false;
}
//Third mistake. Once the BOOL is made false in an if block you have to make it true in the else block, otherwise the value of the BOOL will remain false even if it does not enter the if block.
else{
displayContent = true;
}
NsLog(#"ArrayIndex=[%d];DisplayContent=[%d]",i,displayContent);
}
Happy coding.

Unable to delete items from UIPickerView based upon selection

So, I have a UIPicker view which gets populated from a NSMutableArray as long as the input is not "NULL".
So my picker shows all the values except NULL.
Now, I have a UITextField box and a button. So whatever I type in the text field, and I click the button, if it matches to anything which was there in the NSMutableArray ( which was used to populate UIPickerView ), it sets it to NULL and refreshes the UIPicker so that it doesn't get displayed anymore.
For some reason, I'm able to set the value to NULL(checked using NSLog), but the picker never gets updates, and neither does the NSMutable Array.
-(void) loadthepicker
{
NSMutableArray *getarray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"FilerNamesArray"]];
pickerLoaderArray=[[NSMutableArray alloc] init];
for (int j=0; j<20; j++) {
if ([[getarray objectAtIndex:j] isEqualToString:#"NULL"])
{
// do nothing..don't load
}
else // add that filter to pickerLoaderArray
{
[pickerLoaderArray addObject:[getarray objectAtIndex:j]];
}
} // end of for
[pickerView reloadAllComponents];
[pickerView selectRow:0 inComponent:0 animated:NO];
}
-(NSInteger)numberOfComponentsInPickerView:(NSInteger)component
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)picker numberOfRowsInComponent:(NSInteger)component
{
return [pickerLoaderArray count];
}
-(NSString *)pickerView:(UIPickerView *)picker titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return [pickerLoaderArray objectAtIndex:row];
}
The button:
- (IBAction)deleteButton:(id)sender {
NSUserDefaults *CheckFiltersUsed = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [CheckFiltersUsed integerForKey:#"FiltersUsed"];
if (myInt<=20 && myInt>0) {
NSLog(#"number of filters used before deleting %ld",(long)myInt);
[CheckFiltersUsed setInteger:myInt-1 forKey:#"FiltersUsed"];
[CheckFiltersUsed synchronize];
// get names array
NSMutableArray *getarray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"FilerNamesArray"]];
NSArray *get=getarray;
// at location where name matches with selectedfilter..put NULL
for (int j=0; j<20; j++) {
if ( [[getarray objectAtIndex:j] isEqualToString:_filterToDelete.text] && isFilterDeleted==NO )
{
NSLog(#"------currently %d is %#",j,[getarray objectAtIndex:j]);
[getarray insertObject:#"NULL" atIndex:j];
NSLog(#"------now %d is %#",j,[getarray objectAtIndex:j]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"" message: #"Deleted" delegate: nil cancelButtonTitle:#"Ok" otherButtonTitles:nil]; [alert show];
isFilterDeleted=YES;
[[NSUserDefaults standardUserDefaults] setObject:getarray forKey:#"FilerNamesArray"];
[[NSUserDefaults standardUserDefaults]synchronize];
[self loadthepicker];
}
else
{
NSLog(#"No matching filter name");
}
} // end of for
//now save this array back.
}
else
{
NSUserDefaults *CheckFiltersUsed = [NSUserDefaults standardUserDefaults];
NSInteger myInt = [CheckFiltersUsed integerForKey:#"FiltersUsed"];
NSLog(#"Wrong number of filters!!!... %d",myInt);
}
}
If i get what you are trying to do, you want to delete the equal string from the array and the picker as well. But instead of that you just insert another NSString object into index 'j'
In the deleteButton method:
Instead of this line
[getarray insertObject:#"NULL" atIndex:j];
Call
[getarray removeObjectAtIndex:j];
**Update
In the loadPicker just remove the if statment to check if the string is equal to #"NULL"
So instead of:
for (int j=0; j<20; j++) {
if ([[getarray objectAtIndex:j] isEqualToString:#"NULL"])
{
// do nothing..don't load
}
else // add that filter to pickerLoaderArray
{
[pickerLoaderArray addObject:[getarray objectAtIndex:j]];
}
}
Do:
for(NSString *pickerValue in getarray){
[pickerLoaderArray addObject:pickerValue];
}

How to save order of tabs to NSUserDefaults

I have 8 tabs and am using customizable tabBarItems. So the user can reorder the tabs. Now my question is how do I get the order of the tabs and save that to NSUserDefaults so it remains the same whenever the user exits the app and comes back.
Here is the code I've got so far:
- (void)tabBar:(UITabBar *)tabBar didEndCustomizingItems:(NSArray *)items changed:(BOOL)changed {
NSMutableArray *savedOrder = [NSMutableArray arrayWithCapacity:8];
NSArray *tabOrderToSave = tabBarController.viewControllers;
for (UIViewController *aViewController in tabOrderToSave) {
[savedOrder addObject:aViewController.title];
}
[[NSUserDefaults standardUserDefaults] setObject:savedOrder forKey:#"savedTabOrder"];
}
No errors in that code, it just doesn't work.
What am I doing wrong?
By the way: My app is a tabBarApplication.
EDIT:
Here is what I've done.
Created a tabBar Application
Populated Views with data
Added 8 tabs with different views loaded from controllers
Then added the customizable reordering of tabs
Added the code above to save the tab order
Have do I retrieve that saved data when I relaunch the app?
EDIT 2:
I've been searching around and found a lot of info on this but very little on how.
Here is the code I have now:
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
NSMutableArray *vcArray = [NSMutableArray arrayWithCapacity:6];
NSArray *savedViews = tabBarController.viewControllers;
for (UIViewController *theVC in savedViews){
[vcArray addObject:theVC.title];
}
[[NSUserDefaults standardUserDefaults] setObject:vcArray forKey:#"tabLayout"];
}
- (void)tabBar:(UITabBar *)tabBar didEndCustomizingItems:(NSArray *)items changed:(BOOL)changed {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *tabLayout = [defaults arrayForKey:#"tabLayout"];
NSMutableArray *orderedLayout = [NSMutableArray arrayWithCapacity:6];
NSArray *defaultOrder = tabBarController.viewControllers;
for (int i =0; i < 6; i++){
for (UIViewController *theVC in defaultOrder) {
if ([theVC.title isEqualToString:[tabLayout objectAtIndex:i]]) {
[orderedLayout addObject:theVC];
}
}
}
tabBarController.viewControllers = orderedLayout;
}
Why doesn't this work, and by that I mean after I customize the tabbar and hit stop in Xcode, when I go to run it again it doesn't show my saved order. What in the world am I doing wrong? Is this the correct way to do this?
You're missing the synchronize.
Try this:
- (void)tabBar:(UITabBar *)tabBar didEndCustomizingItems:(NSArray *)items changed:(BOOL)changed {
NSMutableArray *savedOrder = [NSMutableArray arrayWithCapacity:8];
NSArray *tabOrderToSave = tabBarController.viewControllers;
for (UIViewController *aViewController in tabOrderToSave) {
[savedOrder addObject:aViewController.title];
}
[[NSUserDefaults standardUserDefaults] setObject:savedOrder forKey:#"savedTabOrder"];
[[NSUserDefaults standarduserDefaults] synchronize];
}
As #Nekto said - What doesn't work? How do you detect this?
also saving this info won't save your tabbar order... you have to fetch this order from nsuserdefault and generate the tab in that order next time ..
Here's the code I've been using
-(void) saveTabOrder
{
NSMutableArray *savedOrder = [NSMutableArray arrayWithCapacity:6];
NSArray *tabOrderToSave = tabBarController.viewControllers;
for (UIViewController *aViewController in tabOrderToSave)
{
[savedOrder addObject:aViewController.title];
}
[[NSUserDefaults standardUserDefaults] setObject:savedOrder forKey:#"savedTabOrder"];
//[[NSUserDefaults standardUserDefaults] synchronize];
}
// NOTE -- because tabs may change between versions of the app,
// should NOT try to restore tabs if the tab count or names
// differ from the saved version.
- (void)setTabOrderIfSaved {
//return;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *savedOrder = [defaults arrayForKey:#"savedTabOrder"];
NSMutableArray *orderedTabs = [NSMutableArray arrayWithCapacity:6];
if ([savedOrder count] > 0 )
{
for (int i = 0; i < [savedOrder count]; i++) // loop through saved tabs
{
BOOL tabFound = NO;
for (UIViewController *aController in tabBarController.viewControllers) // loop through actual tabs
{
if ([aController.title isEqualToString:[savedOrder objectAtIndex:i]])
{
[orderedTabs addObject:aController];
tabFound = YES;
}
}
if (!tabFound)
{
// so the old tab order doesn't include this tab. Lets bail and use the default ordering
[[NSUserDefaults standardUserDefaults] removeObjectForKey:#"savedTabOrder"];
return;
}
}
tabBarController.viewControllers = orderedTabs;
}
}

Resources