Saving UISwitch Results and NSUserDefaults - ios

I have been trying for days to save the UISwitch state on my tableViewController row to no avail. I have looked at the various stackOverflow questions and responses and the apple documentation, but nothing seems to work in my app.
Here is my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"No" forKey:#"emailSwitch"];
[defaults registerDefaults:appDefaults];
[defaults synchronize];
}
I have the Root.plist in the Settings.bundle set, and this seems to be working and saving the switch results in the app settings but not on the tableViewController. For example, if I switch it to "on" in settings, when I add an object to my tableViewController the switch comes up "off".
Here is the pertinent code in the tableViewController.h file:
#property (nonatomic, getter=isOn) BOOL on;
- (void)toggleValue:(id)sender;
Here is the pertinent code in the tableViewController m file:
- (void)viewWillAppear:(BOOL)animated
{
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"emailSwitch"])
{
[emailSwitch setOn:YES animated:NO];
}
else
{
[emailSwitch setOn:NO animated:NO];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
customTableViewCell *cell = (customTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Code regarding cell contents here
UISwitch *switchObj = [[UISwitch alloc] initWithFrame:CGRectZero];
[switchObj addTarget:self action:#selector(toggleValue:) forControlEvents:(UIControlEventValueChanged | UIControlEventTouchDragInside)];
cell.accessoryView = switchObj;
return cell;
}
-(void)toggleValue:(id)sender
{
[[NSUserDefaults standardUserDefaults] setBool:emailSwitch.on forKey:#"emailSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
When you add an object to the tableViewController and switch the UISwitch to "on", it does not save the "on" status. I have tried various approaches, but nothing is working. If anyone could tell me what I'm doing wrong, I would really appreciate it. Thanks in advance for any help you can offer.

If I understand your question correctly, your toggleValue method should look like this:
-(void)toggleValue:(UISwitch*)sw
{
[[NSUserDefaults standardUserDefaults] setBool:sw.on forKey:#"emailSwitch"];
[[NSUserDefaults standardUserDefaults] synchronize];
}

Related

save and load data in UItableview

I have some problem with saving and loading data in UITableView. After I press button2, I can't find my data that I saved(maybe I didn't save it).
My.h file:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
NSMutableArray * arrayIdea;
NSMutableArray * arrayEdit;
IBOutlet UITableViewCell * cell;
}
#property(nonatomic,strong)IBOutlet UITextField * txtField;
#property(nonatomic,strong)IBOutlet UITableView * tabel1;
-(IBAction)button2:(id)sender;
-(IBAction)button1:(id)sender;
#end
My .m file:
#import "ViewController.h"
#interface ViewController ()<UITextFieldDelegate>
#end
#implementation ViewController
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrayIdea = [[NSMutableArray alloc] init];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (arrayIdea.count > 0) {
return arrayIdea.count;
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell = [tableView dequeueReusableCellWithIdentifier:#"cell1"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell1"];
}
cell.textLabel.text =[NSString stringWithFormat:#"%#", arrayIdea[indexPath.row]];
return cell;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
if(editingStyle == UITableViewCellEditingStyleDelete) {
[arrayIdea removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath,nil] withRowAnimation: UITableViewRowAnimationFade];
}
}
-(IBAction)button1:(id)sender;{
[arrayIdea addObject:self.txtField.text];
[self.tabel1 reloadData];
self.txtField.text = #"";
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:arrayIdea forKey:#"savedstring"];
[defaults synchronize];
}
-(IBAction)button2:(id)sender;{
NSUserDefaults*defaults = [NSUserDefaults standardUserDefaults];
cell.textLabel.text =[defaults objectForKey:#"savedstring"];
}
#end
You need to encode/decode your array to be able to save it/ retrieve it in NSUserDefaults.
Save
NSData *dataSave = [NSKeyedArchiver archivedDataWithRootObject: arrayIdea];
[[NSUserDefaults standardUserDefaults] setObject:dataSave forKey:#"savedstring"];
[[NSUserDefaults standardUserDefaults] synchronize];
Read
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"savedstring"];
NSArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data];
You can save and retrieve like this ..
Save
[[NSUserDefaults standardUserDefaults]setObject:arrayIdea forKey:#"savedstring"];
And retrieve
[[NSUserDefaults standardUserDefaults] objectForKey:#"savedstring"];
In cellForRowAtIndexpath, If you write code like below.
cell.textlabel.text = [[defaults objectForKey:#"saved string"] objectAtIndex:indexPath.row];
instead of passing array.
In numberOfRowsInSection you can pass
[[defalts objectForKey:#"saved string"] count];
You already called table reload method, so there is no need of button 2.
Please try.

Not sure why NSUserdefaults is not saving the results?

I am trying to save checked and remove unchecked tablecells into NSUserdefaults but it seems to ignore it as the NSLog in the for loop never gets called not sure why, is there something wrong with this code? (Everything shows up right and the cells get checked and un-checked correctly)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//setting up nsUser
userDefaults = [NSUserDefaults standardUserDefaults];
//current row text
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellName = cell.textLabel.text;
// Check if current row is selected
Boolean isNowChecked = NO;
if([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark)
{
isNowChecked = YES;
}
if(isNowChecked)
{
NSLog(#"UNCHECKING");
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
//takes away highlight from selection
[tableView deselectRowAtIndexPath:indexPath animated:YES];
//retrieve from nsdefaults
NSMutableArray *arrayOfCategories = [userDefaults objectForKey:#"categories"];
NSMutableArray *categoriesSelected;
//remove from nsuserdefaults
//add to nsuserdefaults
for (NSString* o in arrayOfCategories)
{
NSLog(#"%#",o);
if([o isEqualToString:cellName]) {
} else {
[categoriesSelected addObject:o];
}
}
//set for nsdefaults
[userDefaults setObject:categoriesSelected forKey:#"categories"];
[userDefaults synchronize];
}
else
{
NSLog(#"CHECKING");
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
//takes away highlight from selection
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSMutableArray *categoriesSelected;
//add to array
[categoriesSelected addObject:cellName];
//retrieve from nsdefaults
NSMutableArray *arrayOfCategories = [userDefaults objectForKey:#"categories"];
//add to nsuserdefaults
for (NSString* o in arrayOfCategories)
{
NSLog(#"%#",o);
[categoriesSelected addObject:o];
}
//set for nsdefaults
[userDefaults setObject:categoriesSelected forKey:#"categories"];
[userDefaults synchronize];
}
}
Change this line, otherwise you have an uninitialized Array:
NSMutableArray *categoriesSelected;
to:
NSMutableArray *categoriesSelected = [[NSMutableArray alloc] init];
Update: After looking at your code there are actually quite a few things that should be improved.
You should load the list of checked categories once in viewDidLoad and keep the list in an instance variable.
It's not a good idea to check to see if a cell is currently checked or not by looking at the cell's accessory type. Your data model should tell you which rows are checked.
You have a lot of duplicate code to toggle the checked state of a cell.
Use a set, not an array, to keep track of the checked cells.
Try the following changes:
Add an NSMutableSet instance variable to your class:
NSMutableSet *_checkedCategories;
In viewDidLoad, load the set:
NSArray *checkedCategories = [[NSUserDefault standardUserDefaults] objectForKey:#"categories"];
if (checkedCategories) {
_checkedCategories = [[NSMutableSet alloc] initWithArray:checkedCategories];
} else {
_checkedCategories = [[NSMutableSet alloc] init];
}
Now update your didSelectRow method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellName = ...; // get the cell name from your data model, not the cell
BOOL isChecked = [_checkedCategories containsObject:cellName];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (isChecked) {
[_checkedCategories removeObject:cellName]; // no longer checked
cell.accessoryType = UITableViewCellAccessoryNone;
} else {
[_checkedCategories addObject:cellName]; // now checked
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[[NSUserDefaults standardUserDefaults] setObject:[_checkedCategories allObjects] forKey:#"categories"];
[[NSUserDefaults standardUserDefaults] synchronize];
}

Saving the selected row for UITableView

I'm trying to save the selected row for my UITableView. So, when the user comes back to the screen, it shows their last selection.
This is the code I tried, which, i thought would do the trick:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.lastIndexPathUsed = indexPath;
NSData *responseData = [NSKeyedArchiver archivedDataWithRootObject:indexPath];
[[NSUserDefaults standardUserDefaults] setObject:responseData forKey:#"IndexPathData"];
[[NSUserDefaults standardUserDefaults] synchronize];
[tableView reloadData];
}
Then in my viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
NSData *responseData = [[NSUserDefaults standardUserDefaults]objectForKey:#"IndexPathData"];
NSIndexPath *index = [NSKeyedUnarchiver unarchiveObjectWithData:responseData];
self.lastIndexPath = index;
}
However, responseData hasn't have the index path saved. Its always NULL. Even in the didSelectRowAtIndexPath method.
Anyone know of a better way to do this?
You can save it as two values and recreate the NSIndexPath later:
Save indexPath.row and indexPath.section separately then recreate it with:
[NSIndexPath indexPathForRow:inSection:]
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUserDefaults *userdefaults = [NSUserDefaults standardUserDefaults];
[userdefaults setObject:[NSString stringWithFormat:#"%d",indexPath.row] forKey:#"lastIndexPathUsed"];
}
Then in viewDidLoad Method
-(void)viewDidLoad
{
[super viewDidLoad];
self.lastIndexPath = [[NSUserDefaults standardUserDefaults] objectForKey:#"lastIndexPathUsed"];
}

NSUserDefault not loading in table view

I have a main view with a button that when pressed it adds the url from the web view(like a bookmark) to a table view. The only problem is that its not loading. ive been at it for hours now but cant figure it out. I think i am loading the data in the table view wrong but not quiet sure.
This is the MainViewController.m
- (IBAction)bookmark:(id)sender {
UIActionSheet *actionSheet =
[[UIActionSheet alloc] initWithTitle:[[[[self webView] request] URL]
absoluteString] delegate:nil cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil otherButtonTitles:#"Add", nil];
[actionSheet showInView:self.view];
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSMutableArray *bookmarks = [[[NSUserDefaults standardUserDefaults]
arrayForKey:#"Bookmarks"] mutableCopy];
if (!bookmarks) {
bookmarks = [[NSMutableArray alloc] init];
}
[bookmarks addObject:[[[[self webView]request] URL] absoluteString]];
[[NSUserDefaults standardUserDefaults] setObject:bookmarks
forKey:#"Bookmarks"];
}
}
This is BookmarksViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", bookmarks);
bookmarks = [[[NSUserDefaults standardUserDefaults]
arrayForKey:#"Bookmarks"] mutableCopy];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[[NSUserDefaults standardUserDefaults] setObject:bookmarks forKey:#"Bookmarks"];
cell.textLabel.text = [self.bookmarks objectAtIndex:indexPath.row];
return cell;
}
When your app is first run there is nothing set for the Bookmarks key in NSUserDefaults. So the line:
bookmarks = [[[NSUserDefaults standardUserDefaults]
arrayForKey:#"Bookmarks"] mutableCopy];
in viewDidLoad leaves bookmarks set to nil.
In your action sheet handler you actually deal with this properly.
And one other big problem is the call to:
[[NSUserDefaults standardUserDefaults] setObject:bookmarks forKey:#"Bookmarks"];
in your cellForRowAtIndexPath... method. Why do you update NSUserDefaults every time a cell is needed? Don't do this.
The command [tableView dequeueReusableCellWithIdentifier:CellIdentifier] does NOT always return a cell. It only returns a cell if there is a cell in the reusable-cell queue.
So your method should be:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[[NSUserDefaults standardUserDefaults] setObject:bookmarks forKey:#"Bookmarks"];
cell.textLabel.text = [self.bookmarks objectAtIndex:indexPath.row];
return cell;
}

How to save tableView cell's checkmark after reload view use NSUserDefaults?

I'm new to ios development, and I'm using checkmark for cells in a UITableView.
I want storing checked cell in a NSUserDefaults database, When I reload the app, the checked cell that previously selected will be display, I'm try to defferent ways, but still failed to implement it.
Anybody can help me? I would be highly appreciate it. Sorry, my english is not good.
My code is below:
#import "FirstRowSubview.h"
#interface FirstRowSubview ()
#end
#implementation FirstRowSubview
#synthesize array = _array;
#synthesize lastIndexPath = _lastIndexPath;
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *list = [[NSMutableArray alloc] initWithObjects:#"ffgfgh", #"564654", #"56548", #"fgmjfgmf", #"ggkdj", nil];
self.array = list;
[list release];
}
- (void)viewDidUnload
{
[super viewDidUnload];
self.array = nil;
}
#pragma mark -
#pragma mark - TableView Datasource Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *subviewCells = #"Cells";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:subviewCells];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:subviewCells];
}
NSUInteger oldRow = [_lastIndexPath row];
cell.accessoryType = (indexPath.row == oldRow && _lastIndexPath != nil) ?
UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
cell.textLabel.text = [_array objectAtIndex:indexPath.row];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[NSNumber numberWithInt:_lastIndexPath.row] forKey:#"lastIndexPath"];
[defaults synchronize];
return cell;
}
#pragma mark -
#pragma mark - TableView Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int newRow = [indexPath row];
int oldRow = (_lastIndexPath != nil) ? [_lastIndexPath row] : -1;
if (newRow != oldRow) {
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath];
newCell.accessoryType = UITableViewCellAccessoryCheckmark;
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:_lastIndexPath];
oldCell.accessoryType = UITableViewCellAccessoryNone;
[indexPath retain];
[_lastIndexPath release];
_lastIndexPath = indexPath;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
It can be easy to store and retrieve checked cell(s) information with NSUserDefaults.
NSUserDefaults can store the data interms of Key / Value pair. Here in your case value could be boolean and key could combination of NSString & indexpath.row from UITableView.
You can make a functions like,
- (NSString *)getKeyForIndex:(int)index
{
return [NSString stringWithFormat:#"KEY%d",index];
}
- (BOOL) getCheckedForIndex:(int)index
{
if([[[NSUserDefaults standardUserDefaults] valueForKey:[self getKeyForIndex:index]] boolValue]==YES)
{
return YES;
}
else
{
return NO;
}
}
- (void) checkedCellAtIndex:(int)index
{
BOOL boolChecked = [self getCheckedForIndex:index];
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:!boolChecked] forKey:[self getKeyForIndex:index]];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_array count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Here, you can check for previously checked cells like
static NSString *subviewCells = #"Cells";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:subviewCells];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:subviewCells];
}
cell.textLabel.text = [_array objectAtIndex:indexPath.row];
if([self getCheckedForIndex:indexPath.row]==YES)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
//Use checkedCellAtIndex for check or uncheck cell
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[self checkedCellAtIndex:indexPath.row];
if([self getCheckedForIndex:indexPath.row]==YES)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
P.S. Please, note that, this method will only useful and suggested if order of data from your NSArray will always in same order. Other then NSUserDefaults you've options like SQLite Database or plist file or any other option! Thanks :)
This is a basic example of how to create an array of NSIndexPaths based on the current selection of the table and then saving that array into NSUserDefaults.
-(void)viewDidLoad
{
[super viewDidLoad];
for (NSIndexPath *indexPath in [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"mySavedMutableArray"]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
Here you can add objects to the array as they are selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"mySavedMutableArray"] addObject:indexPath];
[[NSUserDefaults standardUserDefaults] synchronize];
}
Here you'll remove the deselected object from the array.
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"mySavedMutableArray"] removeObject:indexPath];
[[NSUserDefaults standardUserDefaults] synchronize];
}
The simplest way to get your code working is just put one line in view did load method as follow:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults valueForKey:#"lastIndexPath"])
_lastIndexPath = [defaults valueForKey:#"lastIndexPath"];
This will solve your problem :)
Happy Coding :)

Resources