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.
Related
I have two UIViewControllers with tableview. When the first cell loads in the second UIViewController it calls the cellForRowAtIndexPath in the same class but when it loads the second cell it calls the first viewControllers cellForRowAtIndexPath.
My code as follows:
SecondViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NotificationsTableViewCell *cell = [self.notificationsTableView dequeueReusableCellWithIdentifier:#"NotificationCell"];
if(cell == nil)
{
cell = [[NotificationsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"NotificationCell"];
}
NSMutableDictionary *cellData = [self.databaseCall transactionFromDatabase:indexPath.row];
NSLog(#"%#", cellData);
cell.goalNameLabel.text = [cellData objectForKey:#"categoryName"];
NSString *cardTypeId = [cellData objectForKey:#"cardTypeId"];
NSString *tipsId = [cellData objectForKey:#"tipsId"];
if([self.defaultCardTypeId containsObject:cardTypeId])
{
NSUInteger index = [self.defaultCardTypeId indexOfObject:cardTypeId];
[self.defaultCardTypeId replaceObjectAtIndex:index withObject:cardTypeId];
}
else{
[self.defaultCardTypeId addObject:cardTypeId];
}
if([self.defaultTipId containsObject:tipsId])
{
NSUInteger index = [self.defaultCardTypeId indexOfObject:cardTypeId];
[self.defaultTipId replaceObjectAtIndex:index withObject:cardTypeId];
}
else{
[self.defaultTipId addObject:tipsId];
}
if([cardTypeId isEqualToString:#"1"])
{
UIImage *cellImage = [UIImage imageNamed:#"icon2.jpg"];
cell.cardTypeImage.image = cellImage;
cell.cardTypeLabel.text = #"GOOD TO KNOW";
cell.cardTypeLabel.textColor = [UIColor colorWithRed:252/255.0 green:171/255.0 blue:19/255.0 alpha:1];
}
if([cardTypeId isEqualToString:#"2"])
{
UIImage *cellImage = [UIImage imageNamed:#"icon1.jpg"];
cell.cardTypeImage.image = cellImage;
cell.cardTypeLabel.text = #"TO CONSIDER";
cell.cardTypeLabel.textColor = [UIColor colorWithRed:0/255.0 green:191/255.0 blue:243/255.0 alpha:1];
}
cell.notificationCard.layer.cornerRadius = 5;
// Configure the cell...
return cell;
}
FirstViewController:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GoalsCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"GoalsListCell" forIndexPath:indexPath];
if(cell == nil)
{
cell = [[GoalsCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"GoalsListCell"];
}
NSInteger indexOfCategory = [self.databaseCall.arrColumnName indexOfObject:#"CategoryName"];
NSInteger indexOfImage = [self.databaseCall.arrColumnName indexOfObject:#"CategoryImage"];
NSInteger indexOfActive = [self.databaseCall.arrColumnName indexOfObject:#"coulmn"];
//Assigning the contents of cell
cell.goalName.text = [NSString stringWithFormat:#"%#", [[self.arrCategoryTitle objectAtIndex:indexPath.row] objectAtIndex:indexOfCategory]];
NSString *categoryImage = [NSString stringWithFormat:#"%#", [[self.arrCategoryTitle objectAtIndex:indexPath.row] objectAtIndex:indexOfImage]];
NSString *activeStatus = [NSString stringWithFormat:#"%#", [[self.arrCategoryTitle objectAtIndex:indexPath.row] objectAtIndex:indexOfActive]];
UIImage *cellImage = [UIImage imageNamed:categoryImage];
cell.goalImage.image = cellImage;
[cell.favouriteButton addTarget:self action:#selector(favouriteButtonPressed:) forControlEvents:UIControlEventTouchDown];
NSMutableString *selectedRowImage = [[NSMutableString alloc] initWithString:#""];
//Checking whether the category is selected by user or not
if([activeStatus isEqualToString:#"yes"])
{
selectedRowImage = [NSMutableString stringWithFormat:#"starsel.png"];
}
else
{
selectedRowImage = [NSMutableString stringWithFormat:#"stardef.png"];
}
UIImage *favouriteIconImage = [UIImage imageNamed:selectedRowImage];
[cell.favouriteButton setBackgroundImage:favouriteIconImage forState:UIControlStateNormal];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Configure the cell...
return cell;
}
Thanks in advance.
First of all i would say sorry for this stupid question.
The problem is due to the tableview datasource as specifies by #Paulw11, #Onik IV, #Kannan Vora. The secondViewController tableView has the datasource of firstViewController.
I tried this:
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
// this code im trying to toggle already ticked cell
NSString *knownObject = #"YES";
NSArray *alreadyTickedBoxes;
// NSInteger dictIndex= -1;
NSMutableDictionary *dict;
for (dict in self.dataArray){
// dictIndex++;
alreadyTickedBoxes = [dict allKeysForObject:knownObject];
if (alreadyTickedBoxes.count !=0)
break;
}
if(alreadyTickedBoxes.count != 0){
[dict setObject:[NSNumber numberWithBool:NO] forKey:#"checked"];
FeedCell3 *cellToUntick = [dict objectForKey:#"cell"];
UIButton *button = (UIButton *)cellToUntick.accessoryView;
UIImage *newImage = [UIImage imageNamed:#"unticked24"];
[button setBackgroundImage:newImage forState:UIControlStateNormal];
}
// this code toggles tapped cell
NSMutableDictionary *item = [self.dataArray objectAtIndex:indexPath.row] ;
BOOL checked = [[item objectForKey:#"checked"] boolValue];
[item setObject:[NSNumber numberWithBool:!checked] forKey:#"checked"];
FeedCell3 *cell = [item objectForKey:#"cell"];
UIButton *button = (UIButton *)cell.accessoryView;
UIImage *newImage = (checked) ? [UIImage imageNamed:#"unticked24"] : [UIImage imageNamed:#"ticked24"];
[button setBackgroundImage:newImage forState:UIControlStateNormal];
[tableView reloadData];
}
I got it working by just keeping a reference to the last selected index.
#pragma mark - UITableViewDelegate
- (void)checkButtonTapped:(id)sender event:(id)event
{
NSSet *touches = [event allTouches];
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self.feedTableView];
NSIndexPath *indexPath = [self.feedTableView indexPathForRowAtPoint: currentTouchPosition];
if (indexPath != nil)
{
[self tableView: self.feedTableView accessoryButtonTappedForRowWithIndexPath: indexPath];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
// initialise previous index path to current index path
if(self.oldIndexPathRowIndex<0){
self.oldIndexPathRowIndex = indexPath.row;
}
// the following code should toggle previously selected row
if ( self.oldIndexPathRowIndex != indexPath.row) {
NSMutableDictionary *dictAtOldIndex = [self.dataArray objectAtIndex: self.oldIndexPathRowIndex];
BOOL checked = [[dictAtOldIndex objectForKey:#"checked"] boolValue];
NSString *text = [dictAtOldIndex objectForKey:#"text"] ;
NSLog(#"Toggling previously tapped row: %# checked: %d", text, checked);
[dictAtOldIndex setObject:[NSNumber numberWithBool:!checked] forKey:#"checked"];
checked = [[dictAtOldIndex objectForKey:#"checked"] boolValue];
NSLog(#"Previously tapped row: %# toggled to: %d", text, checked);
FeedCell3 *cellToUntick = [dictAtOldIndex objectForKey:#"cell"];
UIButton *button = (UIButton *)cellToUntick.accessoryView;
UIImage *newImage = [UIImage imageNamed:#"unticked40x43"];
[button setBackgroundImage:newImage forState:UIControlStateNormal];
//update current index path
self.oldIndexPathRowIndex = indexPath.row;
}
// this code toggles currently tapped row
NSMutableDictionary *item = [self.dataArray objectAtIndex:indexPath.row] ;
BOOL checked2 = [[item objectForKey:#"checked"] boolValue];
NSString *text = [item valueForKey:#"text"];
NSLog(#"Toggling currently tapped row: %# checked: %d", text, checked2);
[item setObject:[NSNumber numberWithBool:!checked2] forKey:#"checked"];
checked2 = [[item objectForKey:#"checked"] boolValue];
NSLog(#"Currently tapped row: %# toggled to: %d", text, checked2);
FeedCell3 *cell = [item objectForKey:#"cell"];
UIButton *button2 = (UIButton *)cell.accessoryView;
UIImage *newImage2 = (checked2) ? [UIImage imageNamed:#"unticked40x43"] : [UIImage imageNamed:#"ticked40x43"];
[button2 setBackgroundImage:newImage2 forState:UIControlStateNormal];
// NSLog(#"Old Index Path is now row: %d", self.oldIndexPathRowIndex);
[tableView reloadData];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self tableView: self.feedTableView accessoryButtonTappedForRowWithIndexPath: indexPath];
[self.feedTableView deselectRowAtIndexPath:indexPath animated:YES];
}
I have a very weird behavior with a UITableViewController in my project.
Normally it works perfectly but in one specific case it doesn't.
I have a dynamic table view with one custom type of cell. After filling all the data into the data source the table shows all the content correctly. There is a Pull-to-Refresh that updates the data source and table correctly. There are some filter buttons that update the only section with an animation correctly.
But if I click on one the detail view pushes into and if I go back click on one of these filter buttons again all the table view cells update except the ones I clicked. But if I click on this one again the detail view appears with the data of the cell that used to be there.
So the data updates just fine but the visible doesn't.
I would appreciate any suggestions. Thank you
P.S: Yes I do call the deselectRowAtIndexPath: method in the didSelectRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"BANF";
BANFCell *cell = (BANFCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
if (cell == nil) {
cell = [[BANFCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// collect required data
Requisition *req;
// for right section
if ([self.tableView numberOfSections] == 1) {
req = [recent objectAtIndex:indexPath.row];
} else {
if (indexPath.section == 1) {
req = [recent objectAtIndex:indexPath.row];
} else {
req = [notSent objectAtIndex:indexPath.row];
}
}
NSMutableArray *shortTexts = [[NSMutableArray alloc] init];
// get description text and sort short texts ascending
// also the amount and currency
NSString *reqDescript;
NSString *amount;
NSString *currency;
for (Trait *trait in req.traits) {
if ([trait.name isEqualToString:#"DESCRIPTION"] && trait.value.length > 0) {
reqDescript = trait.value;
}
if ([trait.name isEqualToString:#"TOTAL_AMOUNT"] && trait.value.length > 0) {
amount = trait.value;
}
if ([trait.name isEqualToString:#"CURRENCY"] && trait.value.length > 0) {
currency = trait.value;
}
}
NSString *amountAndCurreny;
if (amount) {
NSNumberFormatter *currencyFormatter = [[NSNumberFormatter alloc] init];
[currencyFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[currencyFormatter setCurrencyCode:currency];
amountAndCurreny = [currencyFormatter stringFromNumber:[NSNumber numberWithDouble:amount.doubleValue]];
} else
amountAndCurreny = #"";
cell.amountLabel.text = amountAndCurreny;
NSArray *descriptors = [NSArray arrayWithObjects:[[NSSortDescriptor alloc] initWithKey:#"itm_number"
ascending:YES], nil];
NSArray *orderedArray = [req.positions sortedArrayUsingDescriptors:descriptors];
for (Position *position in orderedArray) {
for (Trait *trait in position.traits) {
if ([trait.name isEqualToString:#"SHORT_TEXT"] && trait.value.length > 0) {
[shortTexts addObject:trait.value];
}
}
}
UIImage *bgImage = [UIImage imageNamed:#"tableBG"];
cell.backgroundView = [[UIImageView alloc] initWithImage:bgImage];
// filling them in
if (req.iD.integerValue < 0) {
[cell.histLabel setText:NSLocalizedString(#"New", nil)];
} else {
[cell.histLabel setText:req.iD.stringValue];
}
[cell.datelabel setText:[labelDateFormatter stringFromDate:req.createDate]];
switch (req.status) {
case ReqStatusNew: [cell.imageView setImage:nil];
break;
case ReqStatusSaved: [cell.imageView setImage:[UIImage imageNamed:#"istGespeichertKiste.png"]];
break;
case ReqStatusApproved: [cell.imageView setImage:[UIImage imageNamed:#"genehmigtKiste.png"]];
break;
case ReqStatusInWFF: [cell.imageView setImage:[UIImage imageNamed:#"workflowKiste.png"]];
break;
case ReqStatusNotApproved: [cell.imageView setImage:[UIImage imageNamed:#"abgelehntKiste.png"]];
break;
case ReqStatusOrdered: [cell.imageView setImage:[UIImage imageNamed:#"istBestelltKiste.png"]];
break;
case ReqStatusDelivered: [cell.imageView setImage:[UIImage imageNamed:#"geliefertKiste.png"]];
break;
}
cell.shortTextLabel.marqueeType = MLContinuous;
cell.shortTextLabel.rate = 50;
cell.shortTextLabel.textAlignment = NSTextAlignmentLeft;
if (reqDescript == nil) {
cell.shortTextLabel.text = [shortTexts componentsJoinedByString:#", "];
} else if (shortTexts.count > 0) {
cell.shortTextLabel.text = [NSString stringWithFormat:#"%#: %#", reqDescript, [shortTexts componentsJoinedByString:#", "]];
} else {
cell.shortTextLabel.text = reqDescript;
}
[cell.shortTextLabel setFrame:CGRectMake(56, 35, 168, 18)];
return cell;
}
In viewWillAppear: I just set the buttons in the navigationcontroller and call
[tableview reloadData]
In viewDidLoad: just adding the delegate of the refresh control
The refresh control just calls [tableview reloadData] after updating the recent and notSent arrays from Core Data
A filter button just calls:
- (IBAction)filterPressed:(UIButton *)sender {
sender.selected = !sender.selected;
NSArray *filters = [dvFilterList componentsSeparatedByString:#","];
if ([[NSUserDefaults standardUserDefaults] boolForKey:[filters objectAtIndex:sender.tag]]){
[[NSUserDefaults standardUserDefaults] setBool:NO
forKey:[filters objectAtIndex:sender.tag]];
} else {
[[NSUserDefaults standardUserDefaults] setBool:YES
forKey:[filters objectAtIndex:sender.tag]];
}
[self updateTableViewData];
// only the section with the recent banfs
NSInteger section = [self numberOfSectionsInTableView:self.tableView] - 1;
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section]
withRowAnimation:UITableViewRowAnimationFade];
}
(updateTableViewData is the method that just updates the recent and notSent arrays from Core Data)
You can try this ,
[tableView reloadData];
You can write this in cellForRowAtIndexPath
BANFCell *cell = (BANFCell *)[tableView dequeueReusableCellWithIdentifier:nil
forIndexPath:indexPath];
I finally found the solution by myself.
In my didSelectRowAtIndexPath: method I call performSegueWithIdentifier: and by giving the selected row as sender variable Xcode is somehow saving just the look of the cell in background that can only be deleted by removing the whole view controller from the stack.
Now I just give self as the sender because I don't need the variable.
So I code this:
[self performSegueWithIdentifier:#"goToReq" sender:self];
Instead of this:
[self performSegueWithIdentifier:#"goToReq" sender:[self tableView:tableView
cellForRowAtIndexPath:indexPath]];
I know this is not the answer for the original question, but might help someone else seeing similar problems.
I've encountered similar behavior with buggy code like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (condition)
{
CustomCell1* cell = [tableView dequeueReusableCellWithIdentifier:#"custom1" forIndexPath:indexPath];
// configure cell
// !! note how "return cell;" is missing !!
}
CustomCell2* cell = [tableView dequeueReusableCellWithIdentifier:#"custom2" forIndexPath:indexPath];
// configure cell
return cell;
}
Was fixed by actually returning the special-case cell from the conditional branch.
As an example, I am trying to load a place name into my top UITableView, called myTableView. On the bottom, I am trying to display only "test2."
Naturally, all the data is being loaded into each UITableView. If I scroll to the bottom of myTableView2, the word "test2" IS shown, but I would like it to be the only thing there.
Is there a way, maybe by delegating different data sources, that I can separate the data I wan in each UITableView? I tried separating by if statements but quickly realized that had no effect.
It seems to me that I may need to set a separate datasource for myTableView2, but I am not sure how to do that...
Code is here:
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
[self setString];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSString *string1 = [dic objectForKey:#"name"];
for (NSDictionary *diction in dic)
{
[array addObject:string1];
}
[[self myTableView] reloadData];
NSString *string2 = [NSString stringWithFormat:#"test2"];
[array addObject:string2];
[[self myTableView2] reloadData];
[indicator stopAnimating];
indicator.hidden=YES;
[indicator removeFromSuperview];
ilabel.hidden = YES;
}
Solved with the code below. The key was to have two different arrays to load the respective data in, and display it at the very bottom where I am able to distinguish between UITableViews with IF statements:
- (void) connectionDidFinishLoading:(NSURLConnection *)connection
{
[self setString];
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil];
NSString *string1 = [dic objectForKey:#"name"];
NSString *string2 = [NSString stringWithFormat:#"test2"];
for (NSDictionary *diction in dic)
{
[array addObject:string1];
[array2 addObject:string2];
[[self myTableView] reloadData];
[[self myTableView2] reloadData];
}
[indicator stopAnimating];
indicator.hidden=YES;
[indicator removeFromSuperview];
ilabel.hidden = YES;
}
-(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];
}
if (tableView == self.myTableView)
{
if ([[array objectAtIndex:indexPath.row] isKindOfClass:[NSNumber class]])
{
cell.textLabel.text = [[array objectAtIndex:indexPath.row] stringValue];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.textAlignment = NSTextAlignmentCenter;
}
else
{
cell.textLabel.text = [array objectAtIndex:indexPath.row];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.textAlignment = NSTextAlignmentCenter;
}
}
if (tableView == self.myTableView2)
{
if ([[array2 objectAtIndex:indexPath.row] isKindOfClass:[NSNumber class]])
{
cell.textLabel.text = [[array2 objectAtIndex:indexPath.row] stringValue];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.textAlignment = NSTextAlignmentCenter;
}
else
{
cell.textLabel.text = [array2 objectAtIndex:indexPath.row];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.textAlignment = NSTextAlignmentCenter;
}
}
return cell;
}
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