On check box click get the table Row ID - Objective c - ios

I am new to objective C. I have a checkbox (its a image) inside a table view. when ever this checkbox is clicked i want get the row (table row id) of the clicked check box.
My application looks like this
objective c
I tried like this but it always gives me the first id
- (void)checkBoxBtnPressed:(id)sender {
UIButton *btn = (UIButton *)sender;
PickupTicketsItemObject *item = [ticketList objectAtIndex:btn.tag];
NSLog(#"item_select %#", item.getTicket_id);
if ([item isSelected]) {
[btn setBackgroundImage:[UIImage imageNamed:#"icon_uncheck"] forState:UIControlStateNormal];
[item setIsSelected:NO];
}else {
[btn setBackgroundImage:[UIImage imageNamed:#"icon_check"] forState:UIControlStateNormal];
[item setIsSelected:YES];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"selected index : %#", indexPath);
NSLog(#"selected index : %ld", (long)indexPath.section);
//Check if assigned to user
PickupTicketsItemObject *item = [ticketList objectAtIndex:indexPath.section];
NSLog(#"selected index : %#", item.ticket_id);
NSLog(#"selected index : %#", item.ticket_assignedto);
//Print all user defaults key and value
//NSLog(#"%#", [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
// get the display name from user defaults
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *displayName;
NSString *AgentName;
if ([userDefaults objectForKey:#"DisplayName"] != nil) {
displayName = [userDefaults objectForKey:#"DisplayName"];
}else { displayName = #"Not defined"; }
AgentName = [#"Agent : " stringByAppendingString:displayName];
NSLog(#"Display Name : %#", displayName);
NSLog(#"Agent Name : %#", AgentName);
NSLog(#"Assigned Name : %#", item.ticket_assignedto);
// ticket is already assigned to agent, send to ticket details page
if ([item.ticket_assignedto isEqualToString:AgentName]) {
NSLog(#"Ticket already assigned to this User.");
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
TicketDetailViewController *ticketDetailViewController = [storyboard instantiateViewControllerWithIdentifier:#"TicketDetailViewController"];
ticketDetailViewController.ticket_id = item.ticket_id;
[kNavigationController pushViewController:ticketDetailViewController animated:YES];
[kMainViewController hideLeftViewAnimated:YES completionHandler:nil];
} else{
NSLog(#"Ticket not assigned to this User.");
// Ask the user to pick the ticket.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SinglePickUpViewController *singlePickUpViewController = [storyboard instantiateViewControllerWithIdentifier:#"SinglePickupVC"];
singlePickUpViewController.ticket_id = item.ticket_id;
[kNavigationController pushViewController:singlePickUpViewController animated:YES];
[kMainViewController hideLeftViewAnimated:YES completionHandler:nil];
}
}
Can some one help me to get the clicked checkboxes table row id. tnx

If you have only one section,
PickupTicketsItemObject *item = [ticketList objectAtIndex:indexPath.section];
always gives you the first element. Try:
PickupTicketsItemObject *item = [ticketList objectAtIndex:indexPath.row];

Please try this it may help you.
In cellForRowAtIndexPath method write this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
btn.tag = indexPath.row + 100;
}
And in your button action method:
- (void)checkBoxBtnPressed:(id)sender {
UIButton *btn = (UIButton *)sender;
NSInteger rowId = btn.tag - 100;
}

Related

pass value in splitview detailview

I have a splitview app, a table with customers to the left and their info on the right so i have to pass witch customer that is clicked and i can't use the name in case of two have the same so im trying to pass over the customer id in the tag property of the cell but i dont get it to work.
Here is where i set the value, i can see it's working when debugging
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
Customer names
NSDate *object = _objects[indexPath.row];
//Customer number
NSString *nr = _kundnr[indexPath.row];
//Customer name
cell.textLabel.text = [object description];
//Customer number
NSInteger Ftgnr = [nr intValue];
//Setting the customer number to cell tag
cell.tag = Ftgnr;
return cell;
}
Here i pick up the cell.tag it's the detailview viewdidload, i tried many different ways to save the id to a variable but the app crashes and i don't know if the value gets passed.
It's working to pick up the description (customer name) but i want the id.
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
// NSString *strCellTag = [NSString stringWithFormat:#"%d", [self.detailItem tag]];
//here im trying to pick up the tag value this is where the app craches
NSInteger Ftgnr = [self.detailItem tag];
// NSString *stringformat = [NSString stringWithFormat:#"%d", Ftgnr];
//Its working to pick up the text from the cell
self.detailDescriptionLabel.text = [self.detailItem description];
}
Thank you for your help!
Add a property to your detail view controller so you can set the id when you set the detail item. Then:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.detailViewController.detailIdentity = _kundnr[indexPath.row];
self.detailViewController.detailItem = _objects[indexPath.row];
}
And then use self.detailIdentity instead of [self.detailItem tag]. And, it's already a string so you don't need to convert to integer and back.
You should probably also:
Rename detailItem to be more specific, like detailDate
Think about creating a custom class to hold the full detailItem (so it contains the identity and the date)
My final code
Masterviewcontroller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDate *object = _objects[indexPath.row];
cell.textLabel.text = [object description];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDate *object = _objects[indexPath.row];
NSDate *kundnr = _kundnr[indexPath.row];
self.detailViewController.detailItem = object;
self.detailViewController.detailIdentity = kundnr;
}
Detailviewcontroller
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)setDetailIdentity:(id)newDetailItentity
{
if (_detailIdentity != newDetailItentity) {
_detailIdentity = newDetailItentity;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
// NSString *stringformat = [NSString stringWithFormat:#"%d", Ftgnr];
self.detailDescriptionLabel.text = [self.detailItem description];
}
if (self.detailIdentity) {
NSString *kundnr = [self.detailIdentity description];
}
}

Wrong indexPath for didSelectRowAtIndex

I parse an product ID via JSON which is then pushed to a detail view and put into an url to parse more information about the selected product but it seems like didSelectRowAtIndexPath returns a wrong indexPath because every time I hit a row it doesn't load the product for the detail view gets the product ID of the row which was retrieved last.
For example I have 5 rows displayed. My logic parses all ids correctly for each row (row 1, row 2, row 3, row 4, row 5). I know hit the first row because I want to get the information linked to row 1 but instead of the information of row one the detail view gets the command to parse information for row 5 because that is the last id which was parsed and then displays the wrong information.
I don't know how to make the didSelectRowAtIndexPath method get the correct information for the correct row.
Here is my Code for didSelectRowAtIndexPath:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIStoryboard *iPhone = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
CJArtikelDetailViewController *artikelView = [iPhone instantiateViewControllerWithIdentifier:#"detail"];
NSString *detail = [NSString stringWithFormat:#"%#", wareID];
artikelView.productID = detail;
[self.navigationController pushViewController:artikelView animated:YES];
[neuheitenTableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"IndexPath: %#", [indexPath description]);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *neuheitenCell = #"neuheitenCell";
CJHomeTableCell *cell = [tableView dequeueReusableCellWithIdentifier:neuheitenCell];
/*
NSNumber *preis = [[arrayArtikelPreis objectAtIndex:indexPath.row] objectForKey:#"preis"];
NSMutableString *test = [NSMutableString stringWithFormat:#"€ %#", preis];
cell.artikelPreis.text = test;
*/
NSString *imageString = [[arrayNeuheiten objectAtIndex:indexPath.row] objectForKey:#"bild"];
//NSLog(#"BildURL: %#", imageString);
NSURL *imageURL = [NSURL URLWithString:imageString];
[cell.artikelImage setImageWithURL:imageURL placeholderImage:[UIImage imageNamed:#""]];
NSDictionary *object = [arrayNeuheiten objectAtIndex:indexPath.row];
//NSLog(#"%#", object);
wareID = [object objectForKey:#"ware_id"];
NSLog(#"Waren ID: %#", wareID);
cell.artikelName.text = [object objectForKey:#"name"];
cell.artikelHersteller.text = [object objectForKey:#"lieferant_name"];
return cell;
}
I have to make the method somehow determine which row was selected but I don't know how and couldn't find information about it in the docs.
Thanks in advance for any help!
Hope this helps
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIStoryboard *iPhone = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
CJArtikelDetailViewController *artikelView = [iPhone instantiateViewControllerWithIdentifier:#"detail"];
NSDictionary *object = [arrayNeuheiten objectAtIndex:indexPath.row];
//NSLog(#"%#", object);
//assign selected product id to wareId here and pass it to detail view controller it will work
wareID = [object objectForKey:#"ware_id"];
NSLog(#"Waren ID: %#", wareID);
NSString *detail = [NSString stringWithFormat:#"%#", wareID];
artikelView.productID = detail;
[self.navigationController pushViewController:artikelView animated:YES];
[neuheitenTableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"IndexPath: %#", [indexPath description]);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *neuheitenCell = #"neuheitenCell";
CJHomeTableCell *cell = [tableView dequeueReusableCellWithIdentifier:neuheitenCell];
/*
NSNumber *preis = [[arrayArtikelPreis objectAtIndex:indexPath.row] objectForKey:#"preis"];
NSMutableString *test = [NSMutableString stringWithFormat:#"€ %#", preis];
cell.artikelPreis.text = test;
*/
NSString *imageString = [[arrayNeuheiten objectAtIndex:indexPath.row] objectForKey:#"bild"];
//NSLog(#"BildURL: %#", imageString);
NSURL *imageURL = [NSURL URLWithString:imageString];
[cell.artikelImage setImageWithURL:imageURL placeholderImage:[UIImage imageNamed:#""]];
//comment out wareId value assigning code here
NSDictionary *object = [arrayNeuheiten objectAtIndex:indexPath.row];//commemted this line by mistake
//NSLog(#"%#", object);
//wareID = [object objectForKey:#"ware_id"];
//NSLog(#"Waren ID: %#", wareID);
cell.artikelName.text = [object objectForKey:#"name"];
cell.artikelHersteller.text = [object objectForKey:#"lieferant_name"];
return cell;
}

Add Cell to "Favorites" TableView from DetailView

I have an existing UITableView that lists a number of cafes in the area. The data for each cafe is being pulled from a MySQL database. When a user clicks on a cafe (cell), it brings a user to a detail view. Currently, users can "Favorite" a cafe by clicking on the star image in each cell (this adds the favorited cell to FavoritesTableView). However, I want users to be able to add a cafe to the FavoritesTableView from the DetailView as well (in other words, "favorite" a cafe from the DetailView). Does anyone know how I would implement this?
Right now, I have the star button in place in my DetailView.m (cafe details):
- (IBAction)buttonpressed:(UIButton *)fave {
if (!checked) {
[checkedButton setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
checked = YES;
}
else if (checked) {
[checkedButton setImage:[UIImage imageNamed:#"unchecked.png"] forState:UIControlStateNormal];
checked = NO;
}
}
ViewController.m (cafes tableview)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strainTableIdentifier = #"StrainTableCell";
StrainTableCell *cell = (StrainTableCell *)[tableView dequeueReusableCellWithIdentifier:strainTableIdentifier];
if (cell == nil)
cell = [[StrainTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strainTableIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"StrainTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
if (tableView == self.searchDisplayController.searchResultsTableView) {
NSLog(#"Using the search results");
cell.titleLabel.text = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Title"];
cell.descriptionLabel.text = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Description"];
cell.ratingLabel.text = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Rating"];
cell.ailmentLabel.text = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Ailment"];
cell.actionLabel.text = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Action"];
cell.ingestLabel.text = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Ingestion"];
NSLog(#"%#", searchResults);
} else {
NSLog(#"Using the FULL LIST!!");
cell.titleLabel.text = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Title"];
cell.descriptionLabel.text = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Description"];
cell.ratingLabel.text = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Rating"];
cell.ailmentLabel.text = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Ailment"];
cell.actionLabel.text = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Action"];
cell.ingestLabel.text = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Ingestion"];
}
NSMutableDictionary *item = [Strains objectAtIndex:indexPath.row];
cell.textLabel.text = [item objectForKey:#"text"];
[item setObject:cell forKey:#"StrainTableCell"];
BOOL checked = [[item objectForKey:#"checked"] boolValue];
NSLog(#"%i",checked);
UIImage *image = (checked) ? [UIImage imageNamed:#"checked.png"] : [UIImage imageNamed:#"unchecked.png"];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
button.frame = frame;
[button setBackgroundImage:image forState:UIControlStateNormal];
[button addTarget:self action:#selector(checkButtonTapped:event:) forControlEvents:UIControlEventTouchUpInside];
button.backgroundColor = [UIColor clearColor];
cell.accessoryView = button;
return cell;
}
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSLog(#"made it here and event is %#",event);
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.StrainTableView];
NSIndexPath * indexPath ;
indexPath = [self.StrainTableView indexPathForRowAtPoint: currentTouchPosition];
NSLog(#"indexpath is below");
NSLog(#"%#",indexPath);
if (indexPath != Nil)
{
NSMutableDictionary *item = [Strains objectAtIndex:indexPath.row];
BOOL isItChecked = [[item objectForKey:#"checked"] boolValue];
NSMutableArray *quickArray = [[NSMutableArray alloc] initWithArray:Strains];
[quickArray replaceObjectAtIndex:indexPath.row withObject:item];
[item setObject:[NSNumber numberWithBool:!isItChecked] forKey:#"checked"];
Strains = [quickArray copy];
[StrainTableView reloadData];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
StrainDetailViewController *detailViewController = [[StrainDetailViewController alloc] initWithNibName:#"StrainDetailViewController" bundle:nil]; if ([searchResults count]) {
detailViewController.title = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Title"];
detailViewController.strainDetail = [searchResults objectAtIndex:indexPath.row];
} else {
detailViewController.title = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Title"];
detailViewController.strainDetail = [Strains objectAtIndex:indexPath.row];
NSLog(#"%#", Strains);
}
[self.navigationController pushViewController:detailViewController animated:YES];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"strains"] != Nil) {
NSData *dataSave = [[NSUserDefaults standardUserDefaults] objectForKey:#"strains"];
Strains = [NSKeyedUnarchiver unarchiveObjectWithData:dataSave];
}
if (favoritesArray == Nil) {
favoritesArray = [[NSMutableSet alloc] init];
}
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"favorites"] != Nil) {
NSData *dataSave = [[NSUserDefaults standardUserDefaults] objectForKey:#"favorites"];
favoritesArray = [NSKeyedUnarchiver unarchiveObjectWithData:dataSave];
}
I'm just not sure what sort of code I would add to this in order to make the "Checked" button add the selected cell from UITableView to FavoritesTableView.
Hope this made sense. Any ideas?
From a maintainability stand point, the approach I generally take might not be the best. However, from an implementation stand point, it's very easy. I pass a reference to my object (in your case, the object for the table view that was selected) to the details view. From the details view, I can update that object by switching the flag. Since this object is the same object as the table view, updating it will also update the table view (you may have to redraw the table view cell). Last, I update the database from the details view.
Edit
So in your code, it would look like this.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
StrainDetailViewController *detailViewController = [[StrainDetailViewController alloc] initWithNibName:#"StrainDetailViewController" bundle:nil]; if ([searchResults count]) {
detailViewController.title = [[searchResults objectAtIndex:indexPath.row] objectForKey:#"Title"];
//YOU'RE ALREADY DOING IT :)
detailViewController.strainDetail = [searchResults objectAtIndex:indexPath.row];
} else {
detailViewController.title = [[Strains objectAtIndex:indexPath.row] objectForKey:#"Title"];
//YOU'RE ALREADY DOING IT :)
detailViewController.strainDetail = [Strains objectAtIndex:indexPath.row];
NSLog(#"%#", Strains);
}
[self.navigationController pushViewController:detailViewController animated:YES];
}
You're already sending a reference to the details view! This makes things easy. In your details view, whenever someone favorites a strain, set the favorite flag for the strainDetail object. This will also update the strainDetail object in the table view. It works like this because you're passing a reference (also referred to as a pointer) to the detail view. In other words, both of your strainDetail objects, aren't objects but pointers to a memory address. If you update either strainDetail, the the memory address for both strainDetail gets changed. Not the strainDetail pointer itself. Here's an link for further explanation https://softwareengineering.stackexchange.com/questions/17898/whats-a-nice-explanation-for-pointers
So your Details view handler will look something like this
- (IBAction)buttonpressed:(UIButton *)fave {
if (!checked) {
[checkedButton setImage:[UIImage imageNamed:#"checked.png"] forState:UIControlStateNormal];
checked = YES;
}
else if (checked) {
[checkedButton setImage:[UIImage imageNamed:#"unchecked.png"] forState:UIControlStateNormal];
checked = NO;
}
//updates in both the detail view and the table view
BOOL isItChecked = [[self.strainDetail objectForKey:#"checked"] boolValue];
[self.strainDetail setObject:[NSNumber numberWithBool:checked] forKey:#"checked"];
}
I also suggest creating a Strain class to hold all of your strain data. Working with dictionaries is not fun, is error prone, and takes forever to figure out what keys you need.
You can save "favorite" state in a global variable/singleton and retrieve it when needed.
This way, even if your table view is deallocated, you won't lose its cells' state.

Problems using custom button in UITableViewCell's Accessory View

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.

TableView doesnt display data after View is changed

I have a problem. At the moment I'm polishing my app and debug it and so on. Something weird happened. Here is how it works: User enters data and gets to the TableView and the data gets displayed. Simple. But as soon as he switches to another view and then back to the TableView, the data is gone! The weird thing is that it didnt happen before. (I redid some codelines, maybe I changed something unknowingly). I have a hinch what it might be, but it would be weird because it worked before. The problem I think lies at the buttonTag line:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// cell.image = selectedImage;
cell.textLabel.font = [UIFont fontWithName:#"Georgia" size:14.0];
if (buttonTag == 9001) {
cell.textLabel.text = [NSString stringWithFormat:#"%# %# %#, %#.", [self.userData objectAtIndex:0], [self.userData objectAtIndex:1], [self.userData objectAtIndex:2], [self.userData objectAtIndex:3]];
}
if (buttonTag == 9002) {
cell.textLabel.text = [NSString stringWithFormat:#"%# %# %#, %#.", [self.userData objectAtIndex:0], [self.userData objectAtIndex:1], [self.userData objectAtIndex:2], [self.userData objectAtIndex:3]];
}
if (buttonTag == 9003) {
cell.textLabel.text = [NSString stringWithFormat:#"%# %# %#,%#.", [self.userData objectAtIndex:0], [self.userData objectAtIndex:1], [self.userData objectAtIndex:2], [self.userData objectAtIndex:3]];
}
return cell;
}
Because he just displays the data when a particular button is pressed. If you change to the TableView without pressing one of those buttons (From a Tabbar e.g.) it doesnt show anything. My question is now: How can I tell the TableView to maintan the data from the last button pressed? (I was thinking NSUserDefaults?)
Here is another ViewController, the one from where you get to the TableView:
- (IBAction)savePressed:(id)sender
{
if (buttonTag == 9001) {
button.tag = 9001;
NSUserDefaults *savetext = [NSUserDefaults standardUserDefaults];
[savetext setObject:Antwort.text forKey:#"hallo"];
[savetext setObject:Antwort2.text forKey:#"hallo2"];
[savetext setObject:Antwort3.text forKey:#"hallo3"];
UIButton *buttonPressed = (UIButton *)sender;
TV *second =[[TV alloc] initWithNibName:nil bundle:nil];
second.buttonTag = buttonPressed.tag;
[self.navigationController pushViewController:second animated:YES];
}
if (buttonTag == 9002) {
button.tag = 9002;
NSUserDefaults *savetext = [NSUserDefaults standardUserDefaults];
[savetext setObject:Antwort.text forKey:#"hallo"];
[savetext setObject:Antwort2.text forKey:#"hallo2"];
[savetext setObject:Antwort3.text forKey:#"hallo3"];
UIButton *buttonPressed = (UIButton *)sender;
TV *second =[[TV alloc] initWithNibName:nil bundle:nil];
second.buttonTag = buttonPressed.tag;
[self.navigationController pushViewController:second animated:YES];
}
if (buttonTag == 9003) {
button.tag = 9003;
NSUserDefaults *savetext = [NSUserDefaults standardUserDefaults];
[savetext setObject:Antwort.text forKey:#"hallo"];
[savetext setObject:Antwort2.text forKey:#"hallo2"];
[savetext setObject:Antwort3.text forKey:#"hallo3"];
UIButton *buttonPressed = (UIButton *)sender;
TV *second =[[TV alloc] initWithNibName:nil bundle:nil];
second.buttonTag = buttonPressed.tag;
[self.navigationController pushViewController:second animated:YES];
}
}
If the data is read & saved in NSUSerDefaults, try
[savetext synchronize]
before pushing to new view.

Resources