I'm writing a simple checklist app. I have two UIViewControllers. The first displays the checklist in a UITableView. I'm using a UIBarButtonItem to push a second view onto the stack to add new tasks. All of the tasks are saved in an array.
Everything works great save for one thing.
If I enter edit mode and delete an item from the table view, the item is removed from the table view and the array--this part seems to be working fine. However, after deleting an item, if I tap the bar button item to add a new task, I run into a problem.
My NSLogs tell me that the new item is added to the array, but when I return to the table view, the deleted item shows up instead of the new item. The table view seems to be reusing the dequeued cell (not sure).
What am I doing wrong?
CLCheckListViewController.m
#import "CLCheckListViewController.h"
#import "CLTaskFactory.h"
#import "CLTaskStore.h"
#import "CLAddTaskViewController.h"
#implementation CLCheckListViewController
{
__weak IBOutlet UITableView *checkList;
}
- (id)init
{
self = [super init];
if (self) {
// add five sample tasks
CLTaskFactory *task1 = [[CLTaskFactory alloc] init];
[task1 setTaskName:#"Task 1"];
[task1 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task1];
CLTaskFactory *task2 = [[CLTaskFactory alloc] init];
[task2 setTaskName:#"Task 2"];
[task2 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task2];
CLTaskFactory *task3 = [[CLTaskFactory alloc] init];
[task3 setTaskName:#"Task 3"];
[task3 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task3];
CLTaskFactory *task4 = [[CLTaskFactory alloc] init];
[task4 setTaskName:#"Task 4"];
[task4 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task4];
CLTaskFactory *task5 = [[CLTaskFactory alloc] init];
[task5 setTaskName:#"Task 5"];
[task5 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task5];
}
return self;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[checkList reloadData];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// create edit button
[[self navigationItem] setLeftBarButtonItem:[self editButtonItem]];
// create title
[[self navigationItem] setTitle:#"Checklist"];
// create add guest button
UIBarButtonItem *bbi = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(pushAddTask)];
[[self navigationItem] setRightBarButtonItem:bbi];
}
- (void)pushAddTask
{
CLAddTaskViewController *advk = [[CLAddTaskViewController alloc] init];
[[self navigationController] pushViewController:advk animated:YES];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[CLTaskStore sharedStore] allTasks] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [checkList dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:#"%#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:#"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:#selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
}
return cell;
}
- (void)didCheckTask:(UIButton *)button
{
CGPoint hitPoint = [button convertPoint:CGPointZero toView:checkList];
hitIndex = [checkList indexPathForRowAtPoint:hitPoint];
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[hitIndex row]];
if (task.didComplete) {
task.didComplete = NO;
} else {
task.didComplete = YES;
}
NSInteger taskCount = [[[CLTaskStore sharedStore] allTasks] count];
for (int i = 0; i < taskCount; i++) {
NSLog(#"%#, status: %#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete]?#"YES":#"NO");
}
// toggle checkbox
button.selected = !button.selected;
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
// set editing mode
if (editing) {
self.navigationItem.title = #"Edit Checklist";
[checkList setEditing:YES];
} else {
self.navigationItem.title = #"Checklist";
[checkList setEditing:NO];
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// remove task
if (editingStyle == UITableViewCellEditingStyleDelete) {
// remove task from CLTaskStore
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]];
[[CLTaskStore sharedStore] removeTask:task];
// remove guest from table view
[checkList deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
// reload table view
//[checkList reloadData];
}
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
[[CLTaskStore sharedStore] moveTaskAtIndex:[sourceIndexPath row] toIndex:[destinationIndexPath row]];
}
#end
CLAddTaskViewController.m
#import "CLAddTaskViewController.h"
#import "CLTaskFactory.h"
#import "CLTaskStore.h"
#implementation CLAddTaskViewController
- (void)viewDidLoad
{
[[self navigationItem] setTitle:#"Add Task"];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// clear first responder
[[self view] endEditing:YES];
// create new task
CLTaskFactory *newTask = [[CLTaskFactory alloc] init];
[newTask setTaskName:[newTaskName text]];
// add new guest to RCGuestStore
[[CLTaskStore sharedStore] addTask:newTask];
}
#end
CLAddTaskFactory.m
#import "CLTaskFactory.h"
#implementation CLTaskFactory
#synthesize taskName;
- (void)setDidComplete:(BOOL)dc
{
didComplete = dc;
}
- (BOOL)didComplete
{
return didComplete;
}
- (NSString *)description
{
// override the description
NSString *descriptionString = [[NSString alloc] initWithFormat:#"%#", taskName];
return descriptionString;
}
#end
CLAddTaskStore.m
#import "CLTaskStore.h"
#import "CLTaskFactory.h"
#import "CLCheckListViewController.h"
#implementation CLTaskStore
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
+ (CLTaskStore *)sharedStore
{
static CLTaskStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
- (id)init
{
self = [super init];
if (self) {
allTasks = [[NSMutableArray alloc] init];
}
return self;
}
- (NSMutableArray *)allTasks
{
return allTasks;
}
- (void)addTask:(CLTaskFactory *)task
{
[allTasks addObject:task];
NSLog(#"Task added: %#", task);
}
- (void)removeTask:(CLTaskFactory *)task
{
// remove the item for the deleted row from the store
[allTasks removeObjectIdenticalTo:task];
NSInteger taskCount = [allTasks count];
NSLog(#"Removed: %#, there are now %d remaining tasks, they are:", task, taskCount);
for (int i = 0; i < taskCount; i++) {
NSLog(#"%#, status: %#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete]?#"YES":#"NO");
}
}
- (void)moveTaskAtIndex:(int)from toIndex:(int)to
{
if (from == to) {
return;
}
CLTaskFactory *task = [allTasks objectAtIndex:from];
[allTasks removeObjectAtIndex:from];
[allTasks insertObject:task atIndex:to];
}
#end
Thanks for your help!
The table view seems to be reusing the dequeued cell
That's exactly what it does; it reuses cells whenever possible. If you had enough items to cause the table view to scroll, you'd also see the same problem.
In -tableView:cellForRowAtIndexPath: you must always set up the cell to display the correct content for the given row index, regardless of whether dequeueReusableCellWithIdentifier: returns a cell or not.
Basically:
If -dequeueReusableCellWithIdentifier: returns nil, create a new cell and add your checkbox button to it.
Then set the cell text and the button state on either this new cell or the cell returned from -dequeueReusableCellWithIdentifier:
Darren is correct. If you look at your code here:
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:#"%#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:#"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:#selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
}
your only setting up the cell if(cell == nil)
Change your code to
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:#"%#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:#"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:#selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
Related
I want every delete button to be tagged with its associated section's headerLabel.text.
This way, when pressing the delete button runs the deleteButtonPressed method, the deleteFromMatchCenter Parse function will use the section's headerLabel.text value as the parameter. I've tried to do it as below, but this doesn't seem to be recognizing the header title properly.
How can I properly associate each delete button with its respective sections header title, and send that over as the parameter?
MatchCenterViewController.m:
#import "MatchCenterViewController.h"
#import <UIKit/UIKit.h>
#interface MatchCenterViewController () <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UITableView *matchCenter;
#end
#implementation MatchCenterViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.matchCenter = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewCellStyleSubtitle];
self.matchCenter.frame = CGRectMake(0,50,320,self.view.frame.size.height-100);
_matchCenter.dataSource = self;
_matchCenter.delegate = self;
[self.view addSubview:self.matchCenter];
_matchCenterArray = [[NSArray alloc] init];
}
- (void)viewDidAppear:(BOOL)animated
{
self.matchCenterArray = [[NSArray alloc] init];
[PFCloud callFunctionInBackground:#"MatchCenter"
withParameters:#{
#"test": #"Hi",
}
block:^(NSArray *result, NSError *error) {
if (!error) {
_matchCenterArray = result;
[_matchCenter reloadData];
NSLog(#"Result: '%#'", result);
}
}];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return _matchCenterArray.count;
}
//the part where i setup sections and the deleting of said sections
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 21.0f;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 21)];
headerView.backgroundColor = [UIColor lightGrayColor];
_searchTerm = [[[[_matchCenterArray objectAtIndex:section] objectForKey:#"Top 3"] objectAtIndex:3]objectForKey:#"Search Term"];
UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 0, 250, 21)];
headerLabel.text = [NSString stringWithFormat:#"%#", _searchTerm];
headerLabel.font = [UIFont boldSystemFontOfSize:[UIFont systemFontSize]];
headerLabel.textColor = [UIColor whiteColor];
headerLabel.backgroundColor = [UIColor lightGrayColor];
[headerView addSubview:headerLabel];
UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
deleteButton.tag = section;
deleteButton.frame = CGRectMake(300, 2, 17, 17);
[deleteButton setImage:[UIImage imageNamed:#"xbutton.png"] forState:UIControlStateNormal];
[deleteButton addTarget:self action:#selector(deleteButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:deleteButton];
return headerView;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Initialize cell
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
// if no cell could be dequeued create a new one
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
// No cell seperators = clean design
tableView.separatorColor = [UIColor clearColor];
// title of the item
cell.textLabel.text = _matchCenterArray[indexPath.section][#"Top 3"][indexPath.row][#"Title"];
cell.textLabel.font = [UIFont boldSystemFontOfSize:14];
// price of the item
cell.detailTextLabel.text = [NSString stringWithFormat:#"$%#", _matchCenterArray[indexPath.section][#"Top 3"][indexPath.row][#"Price"]];
cell.detailTextLabel.textColor = [UIColor colorWithRed:0/255.0f green:127/255.0f blue:31/255.0f alpha:1.0f];
// image of the item
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:_matchCenterArray[indexPath.section][#"Top 3"][indexPath.row][#"Image URL"]]];
[[cell imageView] setImage:[UIImage imageWithData:imageData]];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 65;
}
- (void)deleteButtonPressed:(id)sender
{
// Define the sections title
NSString *sectionName = [self titleForHeaderInSection:indexPath.section];
// Run delete function with respective section header as parameter
[PFCloud callFunctionInBackground:#"deleteFromMatchCenter"
withParameters:
#{#"searchTerm": sectionName,}
block:^(NSDictionary *result, NSError *error) {
if (!error) {
NSLog(#"Result: '%#'", result);
[_matchCenter reloadData];
}
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
You haven't linked your titleForHeaderInSection: method, but you're trying to pass indexPath.section when you don't have access to your indexPath.
Try this
UIButton *deleteButton = (UIButton *)sender;
NSString *sectionName = [self titleForHeaderInSection:deleteButton.tag];
or
NSString *sectionName = _searchTerm = [[[[_matchCenterArray objectAtIndex:deleteButton.tag] objectForKey:#"Top 3"] objectAtIndex:3]objectForKey:#"Search Term"];
In my app, I used a splitView. There are 3 different tables.
When I select any row from 1st Table, the display in the detail view & row remains selected in Left side menu. However, when I select any row from 2nd or 3rd Table, the row is just highlighted with blue color & quickly disappear the Selected blue (i.e. it does not remain Highlighted).
Help me solve this problem.
My code as follow:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier=#"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(tableView == tbl_class)
{
btnEdit1 = [UIButton buttonWithType:UIButtonTypeCustom];
[btnEdit1 setFrame:CGRectMake(220, 15, 20, 20)];
[btnEdit1 addTarget:self action:#selector(btnEditPressed:) forControlEvents:UIControlEventTouchUpInside];
[btnEdit1 setImage:[UIImage imageNamed:#"edit-3-black.png"] forState:UIControlStateNormal];
UIButton *btnDelete = [UIButton buttonWithType:UIButtonTypeCustom];
[btnDelete setFrame:CGRectMake(260, 15, 20, 20)];
[btnDelete addTarget:self action:#selector(btnDelete:) forControlEvents:UIControlEventTouchUpInside];
[btnDelete setImage:[UIImage imageNamed:#"recycle-bin2.png"] forState:UIControlStateNormal];
[btnEdit1 setTag:indexPath.row];
[btnDelete setTag:indexPath.row];
cell.textLabel.text=[NSString stringWithFormat:#"%#",[[classNames objectAtIndex:indexPath.row]valueForKey:#"class_name"]];
if(! isEditing)
{
[cell.contentView addSubview:btnEdit1];
[cell.contentView addSubview:btnDelete];
}
}
if(tableView==tbl_assessment)
{
if (classNames.count > 0)
{
[btnAddAssesst setHidden:NO];
}
else
{
[btnAddAssesst setHidden:YES];
}
cell.textLabel.text=[NSString stringWithFormat:#"%#",[[assessment_list objectAtIndex:indexPath.row]valueForKey:#"assessment_name"]];
}
if (tableView==tbl3)
{
cell.textLabel.text=[arr_result objectAtIndex:indexPath.row];
}
cell.textLabel.font=[UIFont fontWithName:#"Trebuchet MS" size:17.0f];
cell.textLabel.textColor=[UIColor grayColor];
return cell;
}
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
/*
When a row is selected, set the detail view controller's detail item to the item associated with the selected row.
*/
//NSUInteger row = indexPath.row;
if (aTableView==tbl_class)
{
[self.appDelegate.splitViewController viewWillDisappear:YES];
NSMutableArray *viewControllerArray=[[NSMutableArray alloc] initWithArray:[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] viewControllers]];
[viewControllerArray removeLastObject];
self.secondDetailViewController=[[[Class_Vice_ViewController alloc]init]autorelease];
[viewControllerArray addObject:self.secondDetailViewController];
self.appDelegate.splitViewController.delegate = self.secondDetailViewController;
[[NSUserDefaults standardUserDefaults]setInteger:[[[classNames objectAtIndex:indexPath.row]valueForKey:#"class_id"]intValue] forKey:#"psel_class"];
[self databaseOpen];
assessment_list=[[NSMutableArray alloc]init];
NSString *qq=[NSString stringWithFormat:#"select * from Assessment where class_id=%d",[[[classNames objectAtIndex:indexPath.row]valueForKey:#"class_id"]intValue]];
assessment_list=[[database executeQuery:qq]mutableCopy];
[database close];
if (classNames.count > 0)
{
[btnAddAssesst setHidden:NO];
}
else
{
[btnAddAssesst setHidden:YES];
}
if (!assessment_list.count==0) {
[tbl_assessment setHidden:NO];
[btnDelete setHidden:NO];
[tbl_assessment reloadData];
}
[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];
[self.appDelegate.splitViewController viewWillAppear:YES];
[tbl_assessment reloadData];
}
else if (aTableView==tbl_assessment)
{
[self.appDelegate.splitViewController viewWillDisappear:YES];
NSMutableArray *viewControllerArray=[[NSMutableArray alloc] initWithArray:[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] viewControllers]];
[viewControllerArray removeLastObject];
self.thirdDetailViewController=[[[GameAssessment alloc]init]autorelease];
[viewControllerArray addObject:self.thirdDetailViewController];
self.appDelegate.splitViewController.delegate = self.thirdDetailViewController;
[[NSUserDefaults standardUserDefaults]setInteger:[[[assessment_list objectAtIndex:indexPath.row]valueForKey:#"assessment_id"]intValue] forKey:#"ASSESSMENT_ID"];
[self databaseOpen];
assessment_list=[[NSMutableArray alloc]init];
NSString *qq=[NSString stringWithFormat:#"select * from Assessment where class_id=%d",[[NSUserDefaults standardUserDefaults]integerForKey:#"psel_class"]];
assessment_list=[[database executeQuery:qq]mutableCopy];
[database close];
if (!assessment_list.count==0) {
[tbl_assessment setHidden:NO];
[tbl_assessment reloadData];
}
[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];
[self.appDelegate.splitViewController viewWillAppear:YES];
}
else {
[self.appDelegate.splitViewController viewWillDisappear:YES];
NSMutableArray *viewControllerArray=[[NSMutableArray alloc] initWithArray:[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] viewControllers]];
[viewControllerArray removeLastObject];
if (indexPath.row==0) {
self.fifthViewController=[[[ResultStudent_vice alloc]init]autorelease];
[viewControllerArray addObject:self.fifthViewController];
self.appDelegate.splitViewController.delegate = self.fifthViewController;
}
if (indexPath.row==1) {
self.fourthDetailViewController=[[[ResultClass_vice alloc]init]autorelease];
[viewControllerArray addObject:self.fourthDetailViewController];
self.appDelegate.splitViewController.delegate = self.fourthDetailViewController;
}
[[self.appDelegate.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];
[self.appDelegate.splitViewController viewWillAppear:YES];
}
}
Two things to do to keep the row as selected
-deselectRowAtIndexpath should not be there in didselectRowAtIndexpath
Keep an NSMutableArray of NSIndexpath for storing the selected value .When a row is selected add it to array and in the -cellForRowAtIndexpath method check the indexpath is there in cell and if it is there make [tablecell setSelected:YES]; otherwise NO
I am trying to save any of the items as user selects from a uitableview to nsuserdefaults. At that moment only the most recent selection is saved. I would like to have the user to be able to select any of the rows they want and then saved to nsuserdefaults and then use that info anywhere in the app.
thanks for any help
here's my code:
- (void)viewDidLoad
{
[super viewDidLoad];
// categories array
listOfCategories = [[NSMutableArray alloc] init];
[listOfCategories addObject:#"Food & Drinks"];
[listOfCategories addObject:#"Beauty & Wellness"];
[listOfCategories addObject:#"Sports & Fun Activities"];
[listOfCategories addObject:#"Labor & Services"];
[listOfCategories addObject:#"Clothes & Accessories"];
[listOfCategories addObject:#"Education & Training"];
[listOfCategories addObject:#"Products"];
// add label
UIView *viewForHeader = [[UIView alloc] initWithFrame:CGRectMake(0,0,320,40)];
UILabel *categoryLabel = [[UILabel alloc] initWithFrame:CGRectMake(10,0,80,30)];
categoryLabel.text = #"Select all:";
[categoryLabel setFont:[UIFont fontWithName: #"Asap-Bold" size: 14.0f]];
categoryLabel.textColor = [UIColor lightGrayColor];
// add switch
onoff = [[UISwitch alloc] initWithFrame: CGRectMake(100.0f, 0.0f, 100.0f, 0.0f)];
[onoff addTarget: self action: #selector(flipSwitch:) forControlEvents:UIControlEventValueChanged];
[viewForHeader addSubview:onoff];
[viewForHeader addSubview:categoryLabel];
self.tableView.tableHeaderView = viewForHeader;
}
// uiswitch button
- (IBAction) flipSwitch: (id) sender {
onoff = (UISwitch *) sender;
NSLog(#"%#", onoff.on ? #"On" : #"Off");
if (onoff.on) {
for (NSInteger s = 0; s < self.tableView.numberOfSections; s++) {
for (NSInteger r = 0; r < [self.tableView numberOfRowsInSection:s]; r++) {
[self.tableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:r inSection:s]
animated:NO
scrollPosition:UITableViewScrollPositionNone];
}
}
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [listOfCategories count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
} // Configure the cell...
NSString *cellValue = [listOfCategories objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
[cell.textLabel setFont:[UIFont fontWithName: #"Asap-Bold" size: 14.0f]];
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int index = indexPath.row; id obj = [listOfCategories objectAtIndex:index];
//This toggles the checkmark
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
UIImage *image = [UIImage imageNamed:#"icon-tick.png"];
UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
[downloadButton setImage:image forState:UIControlStateNormal];
[downloadButton setFrame:CGRectMake(0, 0, 19, 19)];
[downloadButton setBackgroundColor:[UIColor clearColor]];
[tableView cellForRowAtIndexPath:indexPath].accessoryView = downloadButton;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
//This sets the array
} else
{
cell.accessoryType = UITableViewCellAccessoryNone;
UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeCustom];
[downloadButton setTitle:#"" forState:UIControlStateNormal];
[downloadButton setFrame:CGRectMake(0, 0, 0, 0)];
[tableView cellForRowAtIndexPath:indexPath].accessoryView = downloadButton;
}
// Save text of the selected cell:
UITableViewCell *cellSelected = [tableView cellForRowAtIndexPath:indexPath];
if ([cellSelected.textLabel.text isEqualToString:#"Food & Drinks"]) {
NSString *valueToSave = cellSelected.textLabel.text;
[[NSUserDefaults standardUserDefaults]
setObject:valueToSave forKey:#"preferenceName"];
}
NSString *valueToSave = cellSelected.textLabel.text;
[[NSUserDefaults standardUserDefaults]
setObject:valueToSave forKey:#"preferenceName"];
NSString *savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"preferenceName"];
NSLog(#"savedValue %#", savedValue);
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
// Customize archiver here
[archiver encodeObject:obj forKey:#"keyForYourArrayOfNSIndexPathObjects"];
[archiver finishEncoding];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"keyForYourArrayOfNSIndexPathObjects"];
NSKeyedUnarchiver *unarchiver;
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:
[[NSUserDefaults standardUserDefaults] objectForKey:#"keyForYourArrayOfNSIndexPathObjects"]];
// Customize unarchiver here
categoryItemSelected = [unarchiver decodeObjectForKey:#"keyForYourArrayOfNSIndexPathObjects"];
[unarchiver finishDecoding];
NSLog(#"list of categories selected %#", categoryItemSelected);
}
#end
The issue is because you overridden the previously saved data.
So first of all you need to load saved data:
NSKeyedUnarchiver *unarchiver;
unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:
[[NSUserDefaults standardUserDefaults] objectForKey:#"keyForYourArrayOfNSIndexPathObjects"]];
// Customize unarchiver here
categoryItemSelected = [unarchiver decodeObjectForKey:#"keyForYourArrayOfNSIndexPathObjects"];
[unarchiver finishDecoding];
if (categoryItemSelected == nil) {
//If it isn't been created - then create new array
}
Then add new object:
[categoryItemSelected addObject: obj];
And then save it back to UserDefautls
I'm building a simple checklist in a UITableView. I've added editing capability by placing the usual editing button in the navigation bar. The button turns on editing mode. Editing mode works great until I add custom check boxes (as buttons) in each cell's accessory view. I'm using this code to do it:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:#"%#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:#"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:#selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
// put the index path in the button's tag
checkBox.tag = [indexPath row];
}
return cell;
}
As you can see, I'm using the button's tag to pass the indexPath to my didCheckTask: method:
- (void)didCheckTask:(UIButton *)button
{
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:button.tag];
task.didComplete = YES;
// toggle checkbox
button.selected = !button.selected;
[checkList reloadData];
}
The checkboxes and editing all seem to be working properly on the surface. However, a big problem arises when I enter editing mode, delete an item in the tableView and then try to use a checkbox. For example, if I delete the first item in the tableView and then try to check the last item's checkbox, the program crashes with:
2012-05-06 21:45:40.645 CheckList[16022:f803] * Terminating app due
to uncaught exception 'NSRangeException', reason: '* -[__NSArrayM
objectAtIndex:]: index 4 beyond bounds [0 .. 3]'
I have been trying to figure out the source of this bug, but I'm having no luck. I could really use some help - I'm new to cocoa. Pertinent code follows.
CLTaskFactory.h
#import <Foundation/Foundation.h>
#interface CLTaskFactory : NSObject
{
NSString *taskName;
BOOL didComplete;
}
#property NSString *taskName;
- (void)setDidComplete:(BOOL)dc;
- (BOOL)didComplete;
#end
CLTaskFactory.m
#import "CLTaskFactory.h"
#implementation CLTaskFactory
#synthesize taskName;
- (void)setDidComplete:(BOOL)dc
{
didComplete = dc;
}
- (BOOL)didComplete
{
return didComplete;
}
- (NSString *)description
{
// override the description
NSString *descriptionString = [[NSString alloc] initWithFormat:#"%#", taskName];
return descriptionString;
}
#end
CLTaskStore.h
#import <Foundation/Foundation.h>
#class CLTaskFactory;
#interface CLTaskStore : NSObject
{
NSMutableArray *allTasks;
}
+ (CLTaskStore *)sharedStore;
- (NSMutableArray *)allTasks;
- (void)addTask:(CLTaskFactory *)task;
- (void)removeTask:(CLTaskFactory *)task;
- (void)moveTaskAtIndex:(int)from toIndex:(int)to;
#end
CLTaskStore.m
#import "CLTaskStore.h"
#implementation CLTaskStore
+ (id)allocWithZone:(NSZone *)zone
{
return [self sharedStore];
}
+ (CLTaskStore *)sharedStore
{
static CLTaskStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[super allocWithZone:nil] init];
}
return sharedStore;
}
- (id)init
{
self = [super init];
if (self) {
allTasks = [[NSMutableArray alloc] init];
}
return self;
}
- (NSMutableArray *)allTasks
{
return allTasks;
}
- (void)addTask:(CLTaskFactory *)task
{
[allTasks addObject:task];
}
- (void)removeTask:(CLTaskFactory *)task
{
[allTasks removeObjectIdenticalTo:task];
NSInteger taskCount = [allTasks count];
NSLog(#"Removed: %#, there are now %d remaining tasks, they are:", task, taskCount);
for (int i = 0; i < taskCount; i++) {
NSLog(#"%#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i]);
}
}
- (void)moveTaskAtIndex:(int)from toIndex:(int)to
{
if (from == to) {
return;
}
CLTaskFactory *task = [allTasks objectAtIndex:from];
[allTasks removeObjectAtIndex:from];
[allTasks insertObject:task atIndex:to];
}
#end
CLChecklistViewController.h
#import <Foundation/Foundation.h>
#class CLTaskFactory;
#interface CLCheckListViewController : UIViewController
{
CLTaskFactory *task;
}
- (void)didCheckTask:(UIButton *)button;
#end
CLCheckListViewController.m
#import "CLCheckListViewController.h"
#import "CLTaskFactory.h"
#import "CLTaskStore.h"
#implementation CLCheckListViewController
{
__weak IBOutlet UITableView *checkList;
}
- (id)init
{
self = [super init];
if (self) {
// add five sample tasks
CLTaskFactory *task1 = [[CLTaskFactory alloc] init];
[task1 setTaskName:#"Task 1"];
[task1 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task1];
CLTaskFactory *task2 = [[CLTaskFactory alloc] init];
[task2 setTaskName:#"Task 2"];
[task2 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task2];
CLTaskFactory *task3 = [[CLTaskFactory alloc] init];
[task3 setTaskName:#"Task 3"];
[task3 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task3];
CLTaskFactory *task4 = [[CLTaskFactory alloc] init];
[task4 setTaskName:#"Task 4"];
[task4 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task4];
CLTaskFactory *task5 = [[CLTaskFactory alloc] init];
[task5 setTaskName:#"Task 5"];
[task5 setDidComplete:NO];
[[CLTaskStore sharedStore] addTask:task5];
}
return self;
}
- (void)viewDidLoad
{
[[self navigationItem] setTitle:#"Checklist"];
// create edit button
[[self navigationItem] setLeftBarButtonItem:[self editButtonItem]];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[[CLTaskStore sharedStore] allTasks] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
// put the tasks into the cell
[[cell textLabel] setText:[NSString stringWithFormat:#"%#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]]]];
// put the checkbox into the cell's accessory view
UIButton *checkBox = [UIButton buttonWithType:UIButtonTypeCustom];
[checkBox setImage:[UIImage imageNamed:#"checkbox.png"] forState:UIControlStateNormal];
[checkBox setImage:[UIImage imageNamed:#"checkbox-checked.png"] forState:UIControlStateSelected];
checkBox.frame = CGRectMake(0, 0, 30, 30);
checkBox.userInteractionEnabled = YES;
[checkBox addTarget:self action:#selector(didCheckTask:) forControlEvents:UIControlEventTouchDown];
cell.accessoryView = checkBox;
// put the index path in the button's tag
checkBox.tag = [indexPath row];
}
return cell;
}
- (void)didCheckTask:(UIButton *)button
{
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:button.tag];
task.didComplete = YES;
// toggle checkbox
button.selected = !button.selected;
[checkList reloadData];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
// set editing mode
if (editing) {
self.navigationItem.title = #"Edit Checklist";
[checkList setEditing:YES];
} else {
self.navigationItem.title = #"Checklist";
[checkList setEditing:NO];
}
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath
{
// remove guest from store
if (editingStyle == UITableViewCellEditingStyleDelete) {
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:[indexPath row]];
[[CLTaskStore sharedStore] removeTask:task];
// remove guest from table view
[checkList deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{
[[CLTaskStore sharedStore] moveTaskAtIndex:[sourceIndexPath row] toIndex:[destinationIndexPath row]];
}
#end
Thank you so much for your help and expertise!
edited:
I modified two methods with looping NSLogs to gain some insight. First, CLTaskStore:
- (void)removeTask:(CLTaskFactory *)task
{
[allTasks removeObjectIdenticalTo:task];
NSInteger taskCount = [allTasks count];
NSLog(#"Removed: %#, there are now %d remaining tasks, they are:", task, taskCount);
for (int i = 0; i < taskCount; i++) {
NSLog(#"%#, status: %#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete]?#"YES":#"NO");
}
}
Second, CLTaskListViewController:
- (void)didCheckTask:(UIButton *)button
{
task = [[[CLTaskStore sharedStore] allTasks] objectAtIndex:button.tag];
task.didComplete = YES;
NSInteger taskCount = [[[CLTaskStore sharedStore] allTasks] count];
for (int i = 0; i < taskCount; i++) {
NSLog(#"%#, status: %#", [[[CLTaskStore sharedStore] allTasks] objectAtIndex:i], [[[[CLTaskStore sharedStore] allTasks] objectAtIndex:i] didComplete]?#"YES":#"NO");
}
// toggle checkbox
button.selected = !button.selected;
[checkList reloadData];
}
I noticed two things. If I delete upwards, from bottom to top, there are no issues. I can check anything - everything works. However, if I delete the first row and then check the last row the program crashes. The NSLog from the deletion is clean, its working fine.
If I delete the first row and check the fourth row, the NSLog from CLTaskStore reports row 5 was checked.
This is the problem. The two are definitely out of sequence after the deletion.
Your entire problem stems from the bad idea of using tags to indicate what row a button is in. This is bad enough when you aren't deleting rows from the datasource, but when you are, this is the sort of problem you can run into.
Using the location of the tapped item in the table view, and getting the index path of the location from the table view, is far more robust and works with editable tables and multi-section tables. See sample code in my answer here.
If you do it that way there is no re-indexing necessary.
When the delete button is pressed after entering Edit mode for your tableView, you must remove the corresponding data item from the datasource. Your code shows that you have a removeTask: method, but I don't see where you are actually calling that method to delete the corresponding task entry from your datasource. A good place to do this would be in the tableview:commitEditingStyle:forRowAtIndexPath: method in your view controller.
Since you are deleting the corresponding item in the datasource, further study of the code shows that your checkbox tag values still have their original values. If you delete any tableView item before the last one, then try to check the last one, your didCheckTask method tries to access the original indexPath row value, which now does not exist and causes a bounds exception. If you delete the first two cells, then the last two tableView items will both cause exceptions, and so on.
It wouldn't work in the didCheckTask method, but in the removeTask: method, after you delete the object from your datasource, loop through the remaining objects and set each tag equal to its corresponding array index. In the moveTaskAtIndex:toIndex: method, after you move your array entries around due to the user reordering items, do the same thing -- loop through the array and set each tag equal to its index in the array.
I am using customTableView.I want to reload my tableViewCell with new data from my NSMutableArray.How can i do that?Here is my current Code for the tableView :
tableView.m
//
// GameTableView.m
//
// Created by Mahmudul hasan on 4/6/11.
// Copyright 2011 JU. All rights reserved.
//
#import "GameTableView.h"
#import "BeginingCell.h"
#implementation GameTableView
#synthesize XmlManipulatorObject,QuestionMutableArray,dictionary;
#synthesize _tableView=tableView;
#pragma mark -
#pragma mark Table view data source
-(void)viewDidLoad
{
[super viewDidLoad];
XmlManipulatorObject=[[xmlManipulator alloc] init];
QuestionMutableArray=[[XmlManipulatorObject ReadXml] retain];
dictionary=[[NSMutableDictionary alloc] init];
dictionary = [QuestionMutableArray objectAtIndex:0];
}
-(IBAction) goBack:(id) sender{
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
-(void) btnAction:(id) sender {
NSString *str = ((UIButton*)sender).titleLabel.text;
UIAlertView *alrt=[[UIAlertView alloc]initWithTitle:str message:str
delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil ];
[dictionary removeAllObjects];
[alrt show];
[alrt release];
if(dictionary==nil)
{
NSLog(#"dictionary is nill now");
}
else {
NSLog(#"dictionary is not nil");
}
}
//Method to iterate trough a NSMutableDictionaries in a NSMutableArray
-(NSMutableArray*)GetQuestionByKey:(NSInteger *)key :(NSMutableArray *)Array
{
NSMutableArray *arr;
for (dictionary in Array) {
if (dictionary!=nil) {
arr=[[NSMutableArray alloc] init];
[arr addObject:[dictionary objectForKey:#"option1"]];
}
}
return arr;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"%#",[dictionary objectForKey:#"question"]);
NSLog(#"%#",[dictionary objectForKey:#"option1"]);
NSLog(#"%#",[dictionary objectForKey:#"option2"]);
NSLog(#"%#",[dictionary objectForKey:#"option3"]);
NSLog(#"%#",[dictionary objectForKey:#"option4"]);
static NSString *CellIdentifier = #"BeginingCell";
BeginingCell *cell=(BeginingCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle] loadNibNamed:#"BeginingCell" owner:self options:nil ];
for(id CurrentObject in topLevelObjects)
{
if ([CurrentObject isKindOfClass:[BeginingCell class]]) {
cell=(BeginingCell *) CurrentObject;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
break;
}
}
}
// Configure the cell.
if(indexPath.row==0)
{
cell.myImageView.image = [UIImage imageNamed:#"man_kirstie_alley.jpg"];
cell.SectionTitle.text=[dictionary objectForKey:#"question"];
cell.Option1.text=[dictionary objectForKey:#"option1"];
cell.Option2.text=[dictionary objectForKey:#"option2"];
cell.Option3.text=[dictionary objectForKey:#"option3"];
cell.Option4.text=[dictionary objectForKey:#"option4"];
///For showing the option idntity
[cell.button1 setTitle:#"A." forState:UIControlStateNormal];
[cell.button2 setTitle:#"B." forState:UIControlStateNormal];
[cell.button3 setTitle:#"C." forState:UIControlStateNormal];
[cell.button4 setTitle:#"D." forState:UIControlStateNormal];
///For selecting the correct answer
[cell.ansBtn1 setTitle:#"A" forState:UIControlStateNormal];
[cell.ansBtn2 setTitle:#"B" forState:UIControlStateNormal];
[cell.ansBtn3 setTitle:#"C" forState:UIControlStateNormal];
[cell.ansBtn4 setTitle:#"D" forState:UIControlStateNormal];
[cell.ansBtn1 addTarget:self action:#selector(btnAction:) forControlEvents:UIControlEventTouchUpInside];
[cell.ansBtn4 addTarget:self action:#selector(goBack:) forControlEvents:UIControlEventTouchUpInside];
}
return cell;
}
-(void)viewDidUnload
{
[self dealloc];
}
#end
call
[tblView reloadData];
when you are updating your mutable array.