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"];
}
Related
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.
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];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
myFavsTwo = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:[[[NSUserDefaults standardUserDefaults] objectForKey:#"MyFavoritez"] mutableCopy]]];
[self.tableView reloadData];
NSLog(#"Number of items in my array is: %d", [myFavsTwo count]);
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Number of items in my array is: %d", indexPath.row+1);
[myFavsTwo removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:myFavsTwo] forKey:#"MyFavoritez"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
on delete my app keeps crashing at:
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver
archivedDataWithRootObject:myFavsTwo] forKey:#"MyFavoritez"];
if I 'continue' on my debugging it still works as it should and everything continues like normal...
not getting any error messages either just a 'break point' message
my view will appear looks like this:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
myFavsTwo = [NSKeyedUnarchiver unarchiveObjectWithData:[[[NSUserDefaults standardUserDefaults] objectForKey:#"MyFavoritez"] mutableCopy]];
[self.tableView reloadData];
NSLog(#"Number of items in my array is: %d", [myFavsTwo count]);
}
and the info is coming from here:
- (void)buttonPressed:(id) sender
{
NSMutableArray *myfavs = [[[NSUserDefaults standardUserDefaults] objectForKey:#"MyFavoritez"]mutableCopy];
if(myfavs != nil)
{
NSLog(#"Array found. Contents: %#",myfavs);
}
else
{
myfavs = [[NSMutableArray alloc] initWithCapacity:0];
}
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];
NSData *dataRepresentingSavedArray = [currentDefaults objectForKey:#"MyFavoritez"];
if (dataRepresentingSavedArray != nil)
{
NSArray *oldSavedArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataRepresentingSavedArray];
if (oldSavedArray != nil)
_myfavs = [[NSMutableArray alloc] initWithArray:oldSavedArray];
else
_myfavs = [[NSMutableArray alloc] init];
}
[_myfavs addObject:self.word];
[[NSUserDefaults standardUserDefaults] setObject:[NSKeyedArchiver archivedDataWithRootObject:_myfavs] forKey:#"MyFavoritez"];
[[NSUserDefaults standardUserDefaults] synchronize];
NSLog(#"Number of items in my array is: %d", [_myfavs count]);
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"passFavs"]) {
FavViewController *con = segue.destinationViewController;
con.myFavsTwo = _myfavs; }
}
hope that's not TMI
Have a look at the advice given in this answer - crash on deleteRowsAtIndexPaths in particular it is good practice to bracket your updates to the table view and your data model with [self.tableView beginUpdates] and [self.tableView endUpdates]
In my application I am giving name to my PDF file with the help of AlertView textfield. The names are saving in Array of table list as well as NSUserDefault to access at any time. Now when I am deleting the single row of table the whole list of NSUserDefault is getting disappeared. Could you please suggest some trick over here in my code. Thanks in advance.
Updated code(viewDidLoad) with comments
- (void)viewDidLoad
{
[super viewDidLoad];
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
//Checking previous NSUserDefault. Here I need trick to open the previous updated NSUserDefault
if([[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"%#",[self.tablePdfListArray objectAtIndex:indexPath.row]]] != nil)
{
self.tablePdfListArray = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"%#",[self.tablePdfListArray objectAtIndex:indexPath.row]]]];
}
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 0)
{
if(!self. tablePdfListArray)
{
self.tablePdfListArray = [[NSMutableArray alloc]init];
}
//the below if condition will not allow repeatative string array in tableList and textfield lenth.
if ([[alertView textFieldAtIndex:0].text length] != 0 && ![self.tablePdfListArray containsObject:self.myPDFName])
{
[self.tablePdfListArray insertObject:[NSString stringWithFormat:#"%#", [alertView textFieldAtIndex:0].text] atIndex:0];
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.pdfListnameTable insertRowsAtIndexPaths:#[indexPath]withRowAnimation:UITableViewRowAnimationAutomatic];
//adding table Array in NSUserDefaults
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
[defaults setObject:self.tablePdfListArray forKey:[NSString stringWithFormat:#"%#.",[self.tablePdfListArray objectAtIndex:indexPath.row]]];
[defaults synchronize];
}
}
- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath {
//Deleting single table row. The NSUserDefault should be updated here.
// NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier];
// [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:[NSString stringWithFormat:#"%#.",[self.tablePdfListArray objectAtIndex:indexPath.row]]];
[pdfListnameTable beginUpdates];
[pdfListnameTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[pdfListnameTable deleteSections:indexes withRowAnimation:UITableViewRowAnimationFade];
[pdfListnameTable endUpdates];
}
}
As I understand you are removing all defaults when using
[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain];
Just remove this line of code
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];
}