UITableView crashes when pressing delete button in edit mode - ios

When editing the UITableView, the app usually crashes with this error after someone presses the "delete" button on the uitableviewcell. This usually happens for the first item in the table view, but has happened to others. I'm sorry for being so vague, I can provide any additional infomation. I'm just very confused on why this happens and why it happens when it does.
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray removeObjectAtIndex:]: mutating method sent to immutable object'
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
-(void)viewWillAppear:(BOOL)animated{
[_matchIDS removeAllObjects];
_matchIDS = [[NSMutableArray alloc]init];
_matchIDS = [[NSUserDefaults standardUserDefaults] valueForKey:#"allMatchIDS"];
[self.tableView reloadData];
}
-(void)viewWillDisappear:(BOOL)animated{
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
[defaults setValue:_matchIDS forKey:#"allMatchIDS"];
[defaults synchronize];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _matchIDS.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = _matchIDS[indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_matchIDS removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}

The error results from trying to remove an element from the _matchIDS array, which is immutable.
[_matchIDS removeObjectAtIndex:indexPath.row];
You attempt to make the array mutable here:
-(void)viewWillAppear:(BOOL)animated{
[_matchIDS removeAllObjects];
_matchIDS = [[NSMutableArray alloc]init];
_matchIDS = [[NSUserDefaults standardUserDefaults] valueForKey:#"allMatchIDS"]; // <---
[self.tableView reloadData];
}
but the line marked above replaces _matchIDS, discarding the NSMutableArray you instantiated. You probably want to use the mutableCopy method instead, resulting in something like:
_matchIDS = [[[NSUserDefaults standardUserDefaults] valueForKey:#"allMatchIDS"] mutableCopy];

Related

Xcode commitEditingStyle UITableViewCellEditingStyleDelete is not working

I have a project I have been working on. The code giving me problems worked yesterday and I haven't made any changes to that part of the code since, when I tried to run it today it wasn't working.
The problem is that when I swipe across the cell to delete it it's not detected and commitEditingStyle method is never run.
I also made another project just to test out the commitEditingStyle method and it was working fine. I also cleaned the project(Product -> Clean) and reset the iOS simulator.
What else can I try?
Here's my code, don't worry about NSUserDefaults, that's for saving the changes after you delete the cell.
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return YES; }
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.taskObjects removeObjectAtIndex:indexPath.row];
NSMutableArray *newTaskObjectsData = [[NSMutableArray alloc] init];
for(Model *task in self.taskObjects)
{
[newTaskObjectsData addObject:[self taskObjectAsPropertyList:task]];
}
[[NSUserDefaults standardUserDefaults] setObject:newTaskObjectsData forKey:USER_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
I Hope it's help you
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.taskObjects removeObjectAtIndex:indexPath.row];
NSMutableArray *newTaskObjectsData = [[NSMutableArray alloc] init];
for(Model *task in self.taskObjects)
{
[newTaskObjectsData addObject:[self taskObjectAsPropertyList:task]];
}
[[NSUserDefaults standardUserDefaults] setObject:newTaskObjectsData forKey:USER_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; // please set automatic animation
}
// here you can reload your tableview
[self.tasksTableView reloadData];
I found out what was wrong! I had another method in the viewController that I was not aware was there.
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
Fixed it by setting the return value to UITableViewCellEditingStyleDelete.

UITableView - move people from one section to another

I would like to create a tableview where I can move people from different departments into other departments, and I have some code posted below.
I have an issue with this, I can never seem to get it to get the usual ui gadget to move rows. I don't want the user to edit/delete the rows; simply move them about however the "move" buttons never seem to appear.
Is there something I am doing wrong?
Also I am not sure if I am doing the move code right.
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"Departments";
self.tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.tableView.allowsSelectionDuringEditing = YES;
_objects = [NSMutableArray array];
NSDictionary *sales = #{ #"name" : #"sales",
#"employees" : #[ #"Mike", #"Tom", #"Alex"] };
NSDictionary *marketing = #{ #"name" : #"marketing",
#"employees" : #[ #"Heather", #"Richard", #"Simon"] };
[_objects addObject:sales];
[_objects addObject:marketing];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
}
#pragma mark - IBActions
-(IBAction) editButton:(id)sender
{
[self setEditing:!self.editing animated:YES];
}
#pragma mark - UITableView delegate
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return [_objects count];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *department = [_objects objectAtIndex:section];
NSArray *employees = department[#"employees"];
return [employees count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellId" forIndexPath:indexPath];
// Configure the cell...
NSDictionary *department = [_objects objectAtIndex:indexPath.section];
NSArray *employees = department[#"employees"];
NSString *employeeName = [employees objectAtIndex:indexPath.row];
cell.textLabel.text = employeeName;
return cell;
}
-(NSString *) tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSDictionary *department = [_objects objectAtIndex:section];
return department[#"name"];
}
- (BOOL) tableView: (UITableView *) tableView canEditRowAtIndexPath: (NSIndexPath *) indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
if( fromIndexPath == toIndexPath ) return;
NSDictionary *department = [_objects objectAtIndex:fromIndexPath.section];
NSArray *employees = department[#"employees"];
NSString *employeeName = [employees objectAtIndex:fromIndexPath.row];
[self.tableView beginUpdates];
[_objects removeObjectAtIndex:fromIndexPath.row];
[_objects insertObject:employeeName atIndex:toIndexPath.row];
[self.tableView endUpdates];
[tableView reloadData];
}
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
if (indexPath.section == 1 && [_objects count] > 1)
{
return YES;
}
return NO;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
if(editingStyle == UITableViewCellEditingStyleDelete){
[_objects removeObjectAtIndex:indexPath.row];
NSArray *rows = [NSArray arrayWithObject:indexPath];
[self.tableView beginUpdates];
[self.tableView deleteRowsAtIndexPaths:rows withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView endUpdates];
}
}
call this method after your array initialised. [self.tableView reloadData]
This will load the table data once again.

Save accessory checkmarks on uitableview when users loads view multiple times

So I've implemented a UIViewController with a tableview, and basically it loads as a set of "filters" for my uicollectionview.
Now, when I click on the checkmarks in my tableview, it "filters" my cells accordingly, but now when I reload the view again I want to display the most recent "checkmarks" I've used, or "filters."
I have seen this being implemented with NSUserDefaults, but I have not been able to successfully implement this.
If anyone could help me, that will be greatly appreciated.
CODE
FiltersViewController.m:
#import "FiltersViewController.h"
#interface FiltersViewController ()
#property (nonatomic, strong) NSMutableSet *selectedRowObjects;
//#property (nonatomic, strong) NSArray *filters;
#end
#implementation FiltersViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.selectedRowObjects = [NSMutableSet setWithCapacity:10];
}
- (IBAction)filtersSelected:(id)sender {
[self.delegate filtersSelected:self.selectedRowObjects];
}
- (IBAction)cancelFilterSelection:(id)sender {
[self.delegate filterSelectionCancelled];
}
- (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];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"filter" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *obj = cell.textLabel.text;
if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
[self.selectedRowObjects removeObject:obj];
}
else {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.selectedRowObjects addObject:obj];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
you need to check in cellForRowAtIndexPath also. Write this code in this
if([[NSUserDefaults standardUserDefaults] objectForKey:[self getKeyForIndex:indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
And yes don't forget to call this method in didSelectRowAtIndexPath
[self checkedCellAtIndex:indexPath.row];
Enjoy.
You did almost everything right. You just need to put your logic for reading the NSUserDefault values (for the checked boxes) in the cellForRowAtIndexPath delegate method. That is the method that draws the UITableViewCells when they are displayed on screen. Something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"filter" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
if ([self getCheckedForIndex:indexPath.row])
{
//code to set checkbox
}
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *simpleTableIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = ArrayOfObject[indexPath.row];
NSUserDefaults *ud =[NSUserDefaults standardUserDefaults];
if([[ud objectForKey:#"selectedObjectKey "]isEqualToString:ArrayOfObject[indexPath.row]])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
You have implemented perfectly. You just need to modify you cellForRowAtIndexPath Method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"filter" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
BOOL checked = [self getCheckedForIndex:indexPath.row];
if(checked)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
Also Call [self checkedCellAtIndex:indexPath.row]; from didSelectRowAtIndexPath method of UITableView.
The best way to save tableView CheckMark with NSUserDefaults
#interface TableViewController (){
NSArray *TableTitles;
NSMutableArray *SelectedRows;
}
viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
// table view array
TableTitles = [NSArray arrayWithObjects:#"1",#"2",#"3",#"4",#"5",#"6",#"7",#"8",#"9",#"10", nil];
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
SelectedRows = [NSMutableArray arrayWithArray:[userDef objectForKey:#"SelectedRows"]];
}
cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = TableTitles[indexPath.row];
NSNumber *obj = [NSNumber numberWithInteger:indexPath.row];
if ([SelectedRows containsObject:obj])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
didSelectRowAtIndexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSNumber *obj = [NSNumber numberWithInteger:indexPath.row];
if ([SelectedRows containsObject:obj])
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
[SelectedRows removeObject:obj];
[tableView reloadData];
}else{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
[SelectedRows addObject:obj];
[tableView reloadData];
}
NSUserDefaults *userDef = [NSUserDefaults standardUserDefaults];
[userDef setObject:SelectedRows forKey:#"SelectedRows"];
[userDef synchronize];
}
updated ...
i updated all code with a new way , it's the best way to save TableView CheckMarks and it's now easy and efficient, now only one array is used for saving and loading , code reduced too much :)
You should load data in NSUserDefaults while call cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"filter" forIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:#"%u", indexPath.row];
//You should set accessoryType here by NSUserDefaults data
if ([self getCheckedForIndex:indexPath.row]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
I think what you are looking for is to get the current state of the table for the filters when you enter and exit the view. You need to utilize the - (void)viewWillDisappear:(BOOL)animated to save the current state of the table to your NSUserDefaults, and then use - (void)viewDidLoad and - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath to set the checkmark when the table reloads.
#interface FiltersViewController () {
NSMutableArray *_filterStates;
}
#end
- (void)viewDidLoad {
filterStates = [[NSMutableArray alloc] init];
// get state of your current filters in NSUserDefaults, these should be stored as [NSNumber numberWithBool:]
}
- (void)viewWillDisappear:(BOOL)animated {
// store all of your filters into your NSUserDefaults as [NSNumber numberWithBool:]
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// get your cell from the table
BOOL isChecked = [[_filterStates objectAtIndex:indexPath.row] boolValue];
// set the checkmark based on the current state for this filter
}

indexpath not removing in UITableView

I have UITableView cell for display UITextView text. I need to delete some cell rows text using UITableViewCellEditingStyleDelete. When i use edit button for delete some text i got error.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]];
// NSLog(#"array is %#",myMutableArrayAgain);
return [myMutableArrayAgain count];
}
Delete function:
-(void)editButtonPressed:(UIButton *)button{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
[tableView setEditing:![tableView isEditing] animated:YES];
NSString *buttonTitle = ([tableView isEditing]) ? #"Done" : #"Edit";
[editButton setTitle:buttonTitle forState:UIControlStateNormal];
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
- (void)tableView:(UITableView *)tableView1
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]];
if (editingStyle == UITableViewCellEditingStyleDelete)
{
//first delete this from the db of favorites table
NSLog(#"art id is %#",[myMutableArrayAgain objectAtIndex:indexPath.row]);
NSLog(#"indexpath is %d", indexPath.row);
[myMutableArrayAgain removeObjectAtIndex:indexPath.row];
NSLog(#"remove %d",indexPath.row);
NSArray *indexPathsToRemove = [NSArray arrayWithObject:indexPath];
NSLog(#"indextoremove %#",indexPathsToRemove);
[tableView1 deleteRowsAtIndexPaths:indexPathsToRemove withRowAnimation:UITableViewRowAnimationRight];
}
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
- (void)tableView:(UITableView *)tableView
moveRowAtIndexPath:(NSIndexPath *)fromIndexPath
toIndexPath:(NSIndexPath *)toIndexPath
{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]];
NSString *contentsToMove = [[myMutableArrayAgain objectAtIndex:[fromIndexPath row]] retain];
[myMutableArrayAgain removeObjectAtIndex:[fromIndexPath row]];
[myMutableArrayAgain insertObject:contentsToMove atIndex:[toIndexPath row]];
[contentsToMove release];
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
Error in Nslog:
2013-10-07 14:29:41.939 WorkSa[3689:c07] indexpath is 0
2013-10-07 14:29:41.940 WorkSa[3689:c07] remove 0
2013-10-07 14:29:41.940 WorkSa[3689:c07] indextoremove (
"<NSIndexPath 0x8b44fa0> 2 indexes [0, 0]"
)
2013-10-07 14:29:41.941 WorkSa[3689:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1912.3/UITableView.m:1046
2013-10-07 14:29:41.942 WorkSafeACT[3689:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (7) must be equal to the number of rows contained in that section before the update (7), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
You need to add synchronize statement after deleting, change your function as shown below.
- (void)tableView:(UITableView *)tableView1
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]];
if (editingStyle == UITableViewCellEditingStyleDelete)
{
//first delete this from the db of favorites table
NSLog(#"art id is %#",[myMutableArrayAgain objectAtIndex:indexPath.row]);
NSLog(#"indexpath is %d", indexPath.row);
[myMutableArrayAgain removeObjectAtIndex:indexPath.row];
//Add these 2 lines - Similarly you will need to do in moving items.
[[NSUserDefaults standardUserDefaults] setObject:myMutableArrayAgain forKey:#"save"];
[[NSUserDefaults standardUserDefaults] synchronize];
//Add these 2 lines
[myMutableArrayAgain removeObjectAtIndex:indexPath.row];
NSLog(#"remove %d",indexPath.row);
NSArray *indexPathsToRemove = [NSArray arrayWithObject:indexPath];
NSLog(#"indextoremove %#",indexPathsToRemove);
[tableView1 deleteRowsAtIndexPaths:indexPathsToRemove withRowAnimation:UITableViewRowAnimationRight];
}
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
Also you can use following code to redefine NSLog and have just print variables or strings which will give you method names and all, define these anywhere in appdelegate
#ifdef DEBUG
# define NLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__)
#endif
Check this for more information on NSLog formatting
ok try this,
i am used the normal string values, u better check if the array is correctly loading from the user defaults
#interface ViewController ()<UITableViewDataSource , UITableViewDelegate>
{
NSMutableArray *myMutableArrayAgain; //member mut_array this is the array
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//for example somewhere u are setting the values in the array
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arrayObj = [[NSMutableArray alloc] init];
for(int i = 0 ; i<10 ; i++) {
[arrayObj addObject:[NSString stringWithFormat:#"hello %d",i]];
}
[standardDefaults setObject:arrayObj forKey:#"save"]; //for key save
[arrayObj release];
//fetch the data once becz chancge's that u made to array to be reflected in tableview
//i am fetching the contents hear
myMutableArrayAgain = [[NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]] retain]; //hear u are getting the contents of array
// myMutableArrayAgain = [[NSMutableArray arrayWithObjects:#"hello",#"world",#"happy",#"coding", nil]retain];//insted of ur values i use some string values , insted u can use alloc init method if confused of retain
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] objectForKey:#"save"]]; //dont fech the values to be displayed it is alreday in "myMutableArrayAgain" array
// NSLog(#"array is %#",myMutableArrayAgain);
return [myMutableArrayAgain count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]]; //dont fetch
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
cell.textLabel.text = [myMutableArrayAgain objectAtIndex:indexPath.row]; //use the member array
[cell.textLabel setFont:[UIFont fontWithName:#"Arial-BoldMT" size:14]];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView1 commitEditingStyle (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
// NSMutableArray* myMutableArrayAgain = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"save"]];
if (editingStyle == UITableViewCellEditingStyleDelete)
{
//first delete this from the db of favorites table
// NSLog(#"art id is %#",[myMutableArrayAgain objectAtIndex:indexPath.row]);
NSLog(#"indexpath is %d", indexPath.row);
[myMutableArrayAgain removeObjectAtIndex:indexPath.row];
[tableView1 beginUpdates];
NSLog(#"remove %d",indexPath.row);
// NSArray *indexPathsToRemove = [NSArray arrayWithObject:indexPath];
// NSLog(#"indextoremove %#",indexPathsToRemove);
NSIndexPath *path=[NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section];
[tableView1 deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewScrollPositionBottom];
// [tableView1 deleteRowsAtIndexPaths:indexPathsToRemove withRowAnimation:UITableViewRowAnimationRight];
[tableView1 endUpdates];
}
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
- (void)dealloc
{
[_aTableView release];
[_aButton release];
[super dealloc];
}
- (IBAction)whenButtonTapped:(id)sender
{
NSLog(#">>> Entering %s <<<", __PRETTY_FUNCTION__);
[self.aTableView setEditing:![self.aTableView isEditing] animated:YES];
NSString *buttonTitle = ([self.aTableView isEditing]) ? #"Done" : #"Edit";
[self.aButton setTitle:buttonTitle forState:UIControlStateNormal];
NSLog(#"<<< Leaving %s >>>", __PRETTY_FUNCTION__);
}
#end

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