ios-how to save state of button after application close? - ios

I struggle for few days and searched before.
I have button in UITableViewCell for favorite cell.
How to save state of button (selected button load image "fav.png" and normal button load "unfav.png") after application close?
// BirdsTableViewController.m
// iranbirdtest2
//
// Created by Mehdi on 9/27/15.
// Copyright (c) 2015 Mehdi.n13. All rights reserved.
// after 15 azar-21 mehr
#import "BirdsTableViewController.h"
#import "Bird.h"
#import "GeneralViewController.h"
#import "FavoriteTableViewController.h"
#import "MyManager.h"
//NSMutableArray *favoritesArray;
#interface BirdsTableViewController (){
}
#property (strong, nonatomic) UITabBarController *myTabbarController;
#property (strong, nonatomic) GeneralViewController *myFirstViewController;
#end
#implementation BirdsTableViewController
{
}
- (IBAction)buttonTouchDown:(UIButton *)sender {
sender.selected = !sender.selected; //to switch from selected to unselected
//OR in IBaction we can use:
/*
if ([sender isSelected]) {
[sender setImage:[UIImage imageNamed:#"unfav.png"] forState:UIControlStateNormal];
[sender setSelected:NO];
} else {
[sender setImage:[UIImage imageNamed:#"fav.png"] forState:UIControlStateSelected];
[sender setSelected:YES];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey: #"someKey"];
}
*/
}
- (void) viewDidLoad {
[super viewDidLoad];
for (NSIndexPath *indexPath in [[NSUserDefaults standardUserDefaults] mutableArrayValueForKey:#"mySavedMutableArray"]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
self.title=#"پرندگان ایران";
self.tableView.delegate = self;
self.tableView.dataSource = self;
//create array
birds=[[NSMutableArray alloc]init];
// UIButton* myButton;
Bird *bird=[[Bird alloc]init];
bird.name=#"زنبور خوار";
bird.filename=#"bird1";
bird.detail=#"این قسمت مربوط به توضیح می باشد";
[birds addObject:bird];
bird=[[Bird alloc]init]; //dont forget reuse
bird.name=#"زاغ";
bird.filename=#"bird2";
bird.detail=#"توضیحات مربوط به شماره ۲";
[birds addObject:bird];
bird=[[Bird alloc]init];
bird.name=#"طوطی";
bird.filename=#"bird3";
bird.detail=#"توضیحات مربوط به شماره سومی";
[birds addObject:bird];
//add more later
MyManager *sharedManager = [MyManager sharedManager];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
//this is for page view controller:
self.parentViewController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"common_bg"]];
self.tableView.backgroundColor = [UIColor clearColor];
UIEdgeInsets inset = UIEdgeInsetsMake(5, 0, 0, 0);
self.tableView.contentInset = inset;
[self.tableView setSeparatorStyle:UITableViewCellSelectionStyleNone]; //delete sepreate line odf tables
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) viewWillDisappear:(BOOL)animated{
}
#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 birds.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
// Configure the cell...
tableView.allowsSelection=YES;
Bird *current=[birds objectAtIndex:indexPath.row];
UIImageView *birdImageView = (UIImageView *)[cell.contentView viewWithTag:100];
birdImageView.image = [UIImage imageNamed:current.filename];
UILabel *name = (UILabel *)[cell.contentView viewWithTag:101];
name.text=[current name];
//button code in table view
UIButton *button=(UIButton *) [cell.contentView viewWithTag:103];//fav
[button setImage:[UIImage imageNamed:#"unfav.png"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:#"fav.png"] forState:UIControlStateSelected];
button.frame = CGRectMake(0,0, 50, 50);
button.tag = indexPath.row;
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:button]; // add the button to the cell
[cell.contentView bringSubviewToFront:button];
// Assign our own background image for the cell
UIImage *background = [self cellBackgroundForRowAtIndexPath:indexPath];
UIImageView *cellBackgroundView = [[UIImageView alloc] initWithImage:background];
cellBackgroundView.image = background;
cell.backgroundView = cellBackgroundView;
UIImageView *imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"sepratortable.png"]];
[imgView sizeToFit];
[cell.contentView addSubview:imgView];
return cell;
}
-(void)buttonPressed:(UIButton *)sender
{
NSLog(#"Button Pressed");
MyManager *sharedManager = [MyManager sharedManager];
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell*)sender.superview.superview];
if([sharedManager.favoritesArray containsObject:[birds objectAtIndex:indexPath.row]])
{
[sharedManager.favoritesArray removeObject:[birds objectAtIndex:indexPath.row]];
[self.tableView reloadData];
}
else
{
[sharedManager.favoritesArray addObject:[birds objectAtIndex:indexPath.row]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Do you want to say hello?" message:#"More info..." delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Say Hello",nil];
[alert show];
; //we can remove later
}
//save favorite array in plist.
[NSKeyedArchiver archiveRootObject:sharedManager.favoritesArray toFile:#"/Users/Mehdi/Desktop/Project/Backup/21 mehr/fav.plist"];
NSLog(#"Favoritearray : %d",sharedManager.favoritesArray.count);
/*
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setValue:birds forKey:#"key"];
[[NSUserDefaults standardUserDefaults] synchronize];
*/
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (UIImage *)cellBackgroundForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger rowCount = [self tableView:[self tableView] numberOfRowsInSection:0];
NSInteger rowIndex = indexPath.row;
UIImage *background = nil;
if (rowIndex == 0) {
background = [UIImage imageNamed:#"cell_top.png"];
} else if (rowIndex == rowCount - 1) {
background = [UIImage imageNamed:#"cell_bottom.png"];
} else {
background = [UIImage imageNamed:#"cell_middle.png"];
}
return background;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Navigation
/*
In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
UITabBarController *pvc=[segue destinationViewController];
// Pass the selected object to the new view controller.
//what row selected?
NSIndexPath *path=[self.tableView indexPathForSelectedRow];
Bird *c =birds[path.row];
}
*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
/* if ([segue.identifier isEqualToString:#"ShowGeneralView"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
GeneralViewController *destViewController = segue.destinationViewController;
destViewController.currentbird = [birds objectAtIndex:indexPath.row];
}
*/
self.myTabbarController = (UITabBarController*) [segue destinationViewController];
self.myFirstViewController = [self.myTabbarController.viewControllers objectAtIndex:0];
NSIndexPath *path=[self.tableView indexPathForSelectedRow];
Bird *c =birds[path.row];
_myFirstViewController.currentbird=c;
}
#end
I have no problem for save favorite row after application close.
Problem is with button state that can't save and retrieve.
I know I must use NSUserDefaults, but how?

It seems as though your favorites button is in a cell, and when the button is pressed, you add or remove the favorites from the birds array. You even seem to be storing the plist for a file for persistent storage between app launches. Unless I'm missing something, you need to set the state of the button in the cellForRowAtIndexPath when you build the row. Simply check the favorites array for the cell you are building and if it is in there, set the image to the correct state.
One thing to watch out for is that you need to set it regardless of what you think the default state for the image is. This is because cells are reused (for memory efficency). So let's say you build your cell with a default image state of a gray cell. The user clicks the favorite icon and you set it to the red heart. Then when the user scrolls the cell off the screen, iOS will reuse the cell and the image will still be set to the red image. If you don't explicitly set it to gray if the row is not in your favorites, it will stay red.
Also, as you allude to in your question, you could use NSUserDefaults to store your favorites array, rather than a file (and it would probably be simpler). It would also allow you to use iCloud to sync the user favorites across devices (with a bit more work to handle merge conflicts). There are plenty of resources for how to store data in NSUserDefaults.
In your cellForRowAtIndexPath, you would want to do something like the following:
if([sharedManager.favoritesArray containsObject:[birds objectAtIndex:indexPath.row]])
{
[button setSelected:NO];
} else {
[button setSelected:YES];
}
Also, in your buttonPressed method, you should be toggling the selected state of your button using
sender.selected = !sender.selected;
I would get rid of the (IBAction)buttonTouchDown: method and put all the button handling logic in the buttonPressed method. Having that logic in two places will cause confusion.

Related

delete table view multiple rows from a custom button action using [self.tableView deleteRowsAtIndexPaths withRowAnimation in objective c?

i have a edit button and delete button. when edit button tap table view set editing mode on from left side of table view.i already do this. but when select row and tap to the delete button how to use this method
[self.tableView deleteRowsAtIndexPaths=#"indexpath" withRowAnimation:UITableViewRowAnimationAutomatic];
i can delete data but can not use this method from delete method. i need it because after delete button tap, set editing mode gone, and table view update with animation. if i reload table view its not animated.
Try this
-(void)onButtonTap:(UIButton *)sender {
UITableViewCell *cell = (UITableViewCell *)sender.superview;
NSIndexPath *indexPath = [tableView indexPathForCell:cell];
int index = indexPath.row;
[arrDataSource removeObjectAtIndex:index];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
I created Custom Button Edit and Delete with action.Delete button deletes the row successfully.It works fine.I worked with sample one for your question.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
#property (strong, nonatomic) IBOutlet UITableView *tableViewDeleterow;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
{
NSMutableArray *arrTableData;
}
#end
#implementation ViewController
#synthesize tableViewDeleterow;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
arrTableData = [[NSMutableArray alloc]initWithObjects:#"iPhone",#"iPad",#"iTV",#"iWatch",nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//UITableView DataSource methods
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return arrTableData.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *strCell = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:strCell];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:strCell];
}
//Custom Edit Button
UIButton *btnEdit = [UIButton buttonWithType:UIButtonTypeCustom];
btnEdit.frame = CGRectMake(0,4,100, 20);
[btnEdit setTitle:#"Edit" forState:UIControlStateNormal];
[btnEdit setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnEdit addTarget:self action:#selector(actionEdit:) forControlEvents:UIControlEventTouchUpInside];
btnEdit.tag = indexPath.row;
[cell.contentView addSubview:btnEdit];
//Custom Delete Button
UIButton *btnDelete = [UIButton buttonWithType:UIButtonTypeCustom];
btnDelete.frame = CGRectMake(250,4,100, 20);
[btnDelete setTitle:#"Delete" forState:UIControlStateNormal];
[btnDelete setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[btnDelete addTarget:self action:#selector(actionDelete:) forControlEvents:UIControlEventTouchUpInside];
btnDelete.tag = indexPath.row;
[cell.contentView addSubview:btnDelete];
return cell;
}
-(void)actionEdit:(UIButton *)sender
{
//do stuff here for edit action
}
-(void)actionDelete:(UIButton *)sender
{
UITableViewCell *cell = (UITableViewCell*) sender.superview.superview;
NSIndexPath *indexPath = [tableViewDeleterow indexPathForCell:cell];
NSLog(#"The selected indexPath.row is - %ld",(long)indexPath.row);
[arrTableData removeObjectAtIndex:indexPath.row];
[tableViewDeleterow deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
}
#end
When I delete the 2nd index path delete row,the printed result is
The selected indexPath.row is - 2
At intial
After deleting the second index path row delete button

check mark repeating after some data added....when i make check

i have one table view with left side check button. for first 6 data its working well. when i add three more data to my table view after that when i check my first data my 7 the data also getting check. like wise when i check one data some other data also repeatng with check mark.....
i am using core data....if any one could answer this ......
#interface ViewController ()
{
NSDateFormatter *formatter;
}
#property (strong) NSMutableArray *notes;
#end
#implementation ViewController
#synthesize tableView;
#synthesize addButton;
#synthesize catefetchedResultsController;
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.title = #"My Notes";
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView];
formatter = [[NSDateFormatter alloc] init];
formatter.doesRelativeDateFormatting = YES;
formatter.locale = [NSLocale currentLocale];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterNoStyle;
CATransition *animation = [CATransition animation];
[animation setDuration:2.0];
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromTop];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];
[[addButton layer] addAnimation:animation forKey:#"SwitchToDown"];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// Fetch the devices from persistent data store
NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:#"Notes"];
NSError *error = nil;
self.notes = [[managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
NSSortDescriptor *titleSorter= [[NSSortDescriptor alloc] initWithKey:#"mod_time" ascending:NO];
[self.notes sortUsingDescriptors:[NSArray arrayWithObject:titleSorter]]
;
NSLog(#"Your Error - %#",error.description);
[tableView reloadData];
}
#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 self.notes.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//UIButton *testButton;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
UIButton *testButton = [[UIButton alloc]initWithFrame:CGRectMake(5, 5, 40, 40)];
[testButton setImage:[UIImage imageNamed:#"oval"] forState:UIControlStateNormal];
[testButton setImage:[UIImage imageNamed:#"tick"] forState:UIControlStateSelected];
[testButton addTarget:self action:#selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:testButton];
[cell setIndentationLevel:1];
[cell setIndentationWidth:45];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
// Configure the cell...
NSManagedObject *note = [self.notes objectAtIndex:indexPath.row];
NSDate *date = [note valueForKey:#"mod_time"];
NSString *dateString = [formatter stringFromDate:date];
cell.textLabel.text = [note valueForKey:#"title"];
cell.detailTextLabel.text = dateString;
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
//cell.textLabel.font = [UIFont fontNamesForFamilyName:#"Avenir"];
cell.textLabel.font = [UIFont fontWithName:#"Avenir" size:19.0];
cell.detailTextLabel.font=[UIFont fontWithName:#"Avenir" size:15.0];
}
-(void)buttonTouched:(id)sender
{
UIButton *btn = (UIButton *)sender;
if( [[btn imageForState:UIControlStateNormal] isEqual:[UIImage imageNamed:#"oval"]])
{
[btn setImage:[UIImage imageNamed:#"tick"] forState:UIControlStateNormal];
}
else
{
[btn setImage:[UIImage imageNamed:#"oval"] forState:UIControlStateNormal];
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = (UITableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (IBAction)addButtonPressed:(id)sender {
AddNoteViewController *addNoteVC = [AddNoteViewController new];
// to remove unused warning....
#pragma unused (addNoteVC)
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)cTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSManagedObjectContext *context = [self managedObjectContext];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete object from database
[context deleteObject:[self.notes objectAtIndex:indexPath.row]];
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Can't Delete! %# %#", error, [error localizedDescription]);
return;
}
// Remove device from table view
[self.notes removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (IBAction)btnClick:(id)sender {
}
#end
okay i saw your code and yes the issue is reusability just change this and it will solve your problem
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//UIButton *testButton;
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
UIButton *testButton = [[UIButton alloc]initWithFrame:CGRectMake(5, 5, 40, 40)];
[testButton setImage:[UIImage imageNamed:#"oval"] forState:UIControlStateNormal];
[testButton setImage:[UIImage imageNamed:#"tick"] forState:UIControlStateSelected];
[testButton addTarget:self action:#selector(buttonTouched:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:testButton];
[cell setIndentationLevel:1];
[cell setIndentationWidth:45];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
// Configure the cell...
NSManagedObject *note = [self.notes objectAtIndex:indexPath.row];
NSDate *date = [note valueForKey:#"mod_time"];
NSString *dateString = [formatter stringFromDate:date];
cell.textLabel.text = [note valueForKey:#"title"];
cell.detailTextLabel.text = dateString;
return cell;
}
As cells get reused, you have to prepare them for reuse, or your button will show the previous image when set by another row.
You have to reset the button's (selected) state to match its state for the current row.
You can do this either in tableView:cellForRowAtIbdexPath: or the cell's prepareForReuse method.
Update:
The preferred way to do this is to subclass UITableViewCell and add a UIButton property. This is much better than adding a button to the cell's (contentView, not) view.
In your custom cell, it would look like:
#interface ButtonCell : UITableViewCell
{
#property (weak) IBOutlet UIButton *toggleButton;
}
You can then hookup IBOutlets and IBActions between your storyboard custom cell at its ButtonCell class.
Then it's a simple matter to access the button in your cell by property:
[cell.toggleButton setImage:[UIImage imageNamed:#"oval"] forState:UIControlStateNormal];
[cell.toggleButton setImage:[UIImage imageNamed:#"tick"] forState:UIControlStateSelected];
If each row is supposed to start with that default state where the image is an oval, you would make sure to call those lines from tableView:cellForRowAtIndexPath:
This overwrites any previous toggle state left over from the other row the cell had been used for, so you won't see a tick when you expect an oval :)
Update 2:
Since you have a custom cell you've subclassed that already has a button on it, you no longer have to create or add a button to the cell's (content) view. So, this code from your old approach no longer applies:
[cell addSubview:toogleButton]; // <-- remove this
Next, a UITableViewCell doesn't have a toggleButton property. You need to use your subclassed ButtonCell, which does have a toggleButton property. Dequeue a custom cell (which you've specified and hooked up in the storyboard's dynamic prototype cell).
ButtonCell *cell = [self.tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
Since that method always returns a cell, you can eliminate all the cell == nil conditional code.
Now that you have a custom cell, you set its image.
Since cellForIndexPath is not the place where you toggle its state, you don't want any conditional code there to change it between an oval and a tick.
Your present approach is trying to make the button keep track of its own ticked/oval state, by changing the image it displays. But the cell's button will be reused as cells scroll off the screen. This means the button can't keep track of whether its previous row was ticked or not.
Whenever you need to remember things like whether a row is ticked or not, you want to keep track of this in (an array in) the model.
So, conditionally set your custom button's image, based on the model.
if ([self.noteState objectAtIndex:indexPath.row]) // An array of flags indicating whether a row is checked or not
{
[cell.toggleButton setImage:[UIImage imageNamed:#"tick"] forState:UIControlStateSelected];
}
else
{
[cell.toggleButton setImage:[UIImage imageNamed:#"oval"] forState:UIControlStateSelected];
}
Now your table rows will appropriately be checked off or not.
Since your model has checked state, you would also modernize your buttonTouched code to similarly update the model and toggle the button.
I leave that as an exercise for you. If you've understood everything else up to this point, you won't have any problem applying what you've learned.
Your goal should be to learn and understand what a block of code is meant to do, instead of simply copying and pasting it from StackOverflow.
I appreciate that you want to fix problems with the app you're developing but unless you understand how or why something works, you'll struggle with trying to fix someone else's code.
If you have specific questions, please ask in the comments, and I'll try to answer them!

UITableview not showing content/ empty cells

I'm still learning iOS and this is my first major project, so go easy on me. I'm trying to make a gesture-driven task list. I still have a lot of work to do, but I hope you guys can help me get this working. I'm certain I set the delegate and data source properly, but it's still not showing up...anyway, here's my ViewController.m file.
Thank you in advance!!
#import "AGViewController.h"
#import "AGTaskObject.h"
#import "AGTableViewCell.h"
//#import "AGSettingsViewController.h"
#interface AGViewController ()
#end
#implementation AGViewController {
NSMutableArray *taskItems;
}
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
//Initializing the Array
taskItems = [[NSMutableArray alloc] init];
[taskItems addObject:[AGTaskObject toDoItemWithText:#"Tap the + to add a Task"]];
[taskItems addObject:[AGTaskObject toDoItemWithText:#"Tap the Gear Button to check out settings"]];
[taskItems addObject:[AGTaskObject toDoItemWithText:#"Swipe Right to check off a task"]];
[taskItems addObject:[AGTaskObject toDoItemWithText:#"Swipe Left to Delete a Task"]];
[taskItems addObject:[AGTaskObject toDoItemWithText:#"I <3 Bacon"]];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Table View Delegates
self.tableView.delegate = self;
self.tableView.dataSource = self;
//set the initial background image
self.tableView.backgroundColor = [UIColor clearColor];
self.backgroundImage.image = [UIImage imageNamed:#"blue.png"];
[self.tableView registerClass:[AGTableViewCell class] forCellReuseIdentifier:#"cell"];
//Get rid of empty cells at bottom of tableview
// self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
// Long Press Gesture to rearrange cells
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressGestureRecognized:)];
[self.tableView addGestureRecognizer:longPress];
// // Tap Gesture to add a new cell
// UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(<#selector#>)];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Button Press (IB)Actions
- (IBAction)settingsButtonPressed:(UIButton *)sender
{
[self performSegueWithIdentifier:#"toSettingsViewController" sender:nil];
}
- (IBAction)addTaskButtonPressed:(UIButton *)sender
{
}
#pragma mark - UITableView Configuration
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [taskItems count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"cell";
//re-Use or create a tableview cell
AGTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier
forIndexPath:indexPath];
/* if (cell == nil) {
cell = [[AGTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
*/
//Make the cells clear to show the background image
cell.backgroundColor = [UIColor clearColor];
//default font color will be white
cell.textLabel.textColor = [UIColor whiteColor];
//Set the task for each cell in the tableview
AGTaskObject *item = taskItems[indexPath.row];
//set the text
cell.delegate = self;
cell.taskObject = item;
// Recall final cell
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.backgroundColor = [self colorForIndex:indexPath.row];
}
#pragma mark - TableItem Delete
-(void)toDoItemDeleted:(id)taskobject {
// use the UITableView to animate the removal of this row
NSUInteger index = [taskItems indexOfObject:taskobject];
[self.tableView beginUpdates];
[taskItems removeObject:taskobject];
[self.tableView deleteRowsAtIndexPaths:#[[NSIndexPath indexPathForRow:index inSection:0]]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
}
Storyboards don't use initWithNibName (even though Xcode creates it pointlessly) so your array is empty. Try moving it to viewDidLoad

Populating UITextView with Specific Info when UITableView Row is Selected

I have a UITableView and another view. The other view has a UITextView that I want populated with different text depending on what row in the table view is selected. I know how to do it if I create different views for all of the different text options. If I did it that way, I could just have that view open when the row is tapped. I'm just wanting to avoid having to create a bunch of different views and just use one that gets loaded with different text depending on row tapped in the table view. I guess I just need to know how the view with the text view can access indexPath.row from the table view. Any suggestions?
EDIT: Here is my code.
LHRRoster.m
#import "LHRRoster.h"
#import "CustomCellBackground.h"
#import "OnMyHonor.h"
#import "AVA.h"
#import "Receivers.h"
#import "BandDetailView.h"
#interface LHRRoster ()
#end
#implementation LHRRoster
{
NSMutableArray *mbTableData;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
mbTableData = [NSMutableArray arrayWithObjects:#"Aesthetics Versus Architecture", #"On My Honor", #"Receivers", #"Skyscraper Stereo", #"California", #"Late Ones", #"Uh-Huh Baby Yeah", #"Danielle Bouchard", #"Chris Karrer", #"Joey Blue", #"The Codas", #"Your Favorite Hero", #"Nixon", #"Skam Impaired", #" SaySomethingHugeOnFire", #"Adore Me Not", #"Common Collective", #"The Royal Tees", #"The Gravetones", #"Bush League", #"Rock & Roll Television", #" Tastyface", #"The Lips", #"Mercy Academy", #"Audiostrobelight", nil];
self.title = #"LHR Roster";
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [mbTableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *mbTableIdentifier = #"SimpleTableItem";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:mbTableIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:mbTableIdentifier];
cell.textLabel.font=[UIFont systemFontOfSize:14.0];
}
cell.backgroundView = [[CustomCellBackground alloc] init];
cell.selectedBackgroundView = [[CustomCellBackground alloc] init];
cell.textLabel.backgroundColor = [UIColor clearColor];
cell.textLabel.highlightedTextColor = [UIColor darkGrayColor];
cell.textLabel.text = [mbTableData objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BandDetailView *detailView = [[BandDetailView alloc]initWithNibName:#"BandDetailView" bundle:nil];
if (indexPath.row == 0)
{
detailView.title = #"Aesthetics vs Architecture";
UIImage *image = [UIImage imageNamed: #"AVA.png"];
[detailView.bandPic setImage:image];
NSString *bio = #"";
[detailView.bandInfo setText:bio];
[self.navigationController pushViewController:detailView animated:YES];
}
}
#end
You are getting the selected cell object, just pass that object to the TextView and it will dynamically load selected cell data.An important thing to note,first push view controller then pass data to that controller.In your code you have passed data first,then pushed view controller, that doesnt work
MVC - model, view, controller. Your data is model. The table view and the text view are view. Your UIViewController is the controller. It does all the work.
Implement didSelectRowAtIndexPath in the controller, which is the delegate of the table view. Now you know that a row of the table was selected, and you know which row it is. So pull the desired text out of your model and stick it in the UITextView.
Expand your didSelectRowAtIndexPath to also modify your UITextView.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
**myUiTextView.text = somethingBasedOnTheRowSelected[indexPath.row];** <-- new code here
// followed by your existing code
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BandDetailView *detailView = [[BandDetailView alloc]initWithNibName:#"BandDetailView" bundle:nil];
if (indexPath.row == 0)
{
detailView.title = #"Aesthetics vs Architecture";
UIImage *image = [UIImage imageNamed: #"AVA.png"];
[detailView.bandPic setImage:image];
NSString *bio = #"";
[detailView.bandInfo setText:bio];
[self.navigationController pushViewController:detailView animated:YES];
}
**myUiTextView.text =[yourarray indexPath.row];
}
follow this code this code might help you.
Just Add your code is
yourtextfieldname.text=[yourarrayname objectAtIndex:indexpath.row];
and get your selected row textfield data in your textfield.
i hope this code is useful for you .

Two UITableView Controllers in SplitViewController in iPad, Delegate

Hi This is my first iPad app and trying to port my iphone app to iPad.
I have followed all the tutorials from http://www.raywenderlich.com/ still having a problem.
Also review this question and still having the problem . Splitviewcontroller with two tableviews, delegate problem
Basically, I have two UITableViewControllers in SplitViewController and when I click the tableview cell in root view controller, I want to populate the details in DetailsViewController in Right side on another Tableview.
The problem is I can manage to pass the array data from but I can't call tableview reload method.
Here is the code
LeftViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
if (row == 0){
NSLog(#"Row 0 Pressed");
RightViewController *rightvc = [self.storyboard instantiateViewControllerWithIdentifier:#"displayenglish"];
_locallayleft = [ConversationDatabase database].conversationsInfos;
NSLog(#"Just pushed the array");
rightvc.detailItem = _locallayleft;
rightvc.title = #"Greetings";
}
else if (row == 1) {
NSLog(#"Row 1 Pressed");
RightViewController *rightvc = [self.storyboard instantiateViewControllerWithIdentifier:#"displayenglish"];
_locallayleft = [ConversationDatabase database].conversationsInfosgeneral;
rightvc.detailItem = _locallayleft;
rightvc.title = #"General Conversation";
}
-----------------------------------------------------------------------------------------
RightViewController
- (void)setDetailItem:(NSArray *)newDetailItem
{
if(_detailItem != newDetailItem) {
_detailItem = newDetailItem;
[self configureView];
}
}
- (void)configureView
{
if (self.detailItem) {
self.locallay = self.detailItem;
_listOfCoversation = [[NSMutableArray alloc] init];
for (ConversationInEnglish *c in _locallay)
{
NSString *english = c.english;
NSLog(#"setDetails Item get called");
NSLog(#"%#",english);
[_listOfCoversation addObject:english];
}
[self.tableView reloadData];
NSLog(#"Trying to reload TableView");
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureView];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [_locallay count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"English";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
ConversationInEnglish *con = _locallay [indexPath.row];
_englishLabel = (UILabel *) [cell viewWithTag:200];
_englishLabel.text = con.english;
NSLog(#"My data from cell %#",con.english );
[_englishLabel setFont:[UIFont fontWithName:#"Open Sans" size:22]];
_myanmarLabel = (UILabel *) [cell viewWithTag:300];
[_myanmarLabel setFont:[UIFont fontWithName:#"TharLon" size:17]];
_tonebasedLabel = (UILabel *) [cell viewWithTag:400];
_tonebasedLabel.text = con.tone_based;
UIColor *background = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:#"tableviewcell.png"]];
self.tableView.backgroundColor = background;
return cell;
}
It looks like when you tap a row in the table on the left, instead of updating the table on the right, you're instantiating a whole new table from the storyboard instead, but not replacing the one on the right with it.
There isn't enough context here to say exactly how to fix it, but what you'd want to do is when you tap a row in the table on the left, update the table on the right by setting its detailItem property.
You'll need access to the other table view. There are a few ways to do this depending on how you've got your application set up - if you're using the same left table view on both the iPhone and iPad then you'll probably need some conditional code to locate it, for example:
if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) {
DetailViewController *detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
detailViewController.detailItem = newDetailItem;
}
Or you could configure it through the storyboard. Either way, the key is to find and update the existing table view instead of instantiating a new one from the storyboard.

Resources