How to update a cell in a UITableView? - objective-c

I'm using Delegate methods to get data from child view and want to dynamically edit my table in the root view.
So I would like to do something like this in my viewWillAppear method :
[myTable setCell:newCell atIndex:i];
What should I do ? Thanks a lot

put your code in between:
[myTable beginUpdates];
//your code
[myTable setCell:newCell atIndex:i];
//your code end
[myTable endUpdates];

Well, finally I made it using :
[cellules beginUpdates];
[cellules reloadData];
[cellules endUpdates];
I used reloadData because it's a little TableView (3 cells), for big TableViews this should be better :
– reloadRowsAtIndexPaths:withRowAnimation:
Thanks anyway !

Related

ios - reloadData TableView & Core Data

I am having a bit of trouble with reloading my tableView which is set in a UIViewController.
It is populated with CoreData (This works)
It is also got a custom TableViewCell for some design purposes
Now normally what I would use is this : [_mainTableView reloadData];
That does not work this time.
Is this because of the custom Cell or is Core Data's FetchRequest which loads fine initially and shows the data when I relaunch the app??
I have seen several questions and tutorials on SO and Google, but none of them seem to work in my case.
I have also explored these methods:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
found here: beignUpdates
Any advice is appreciated.
Have you synthesized your table view? Please try this:
[self.mainTableView reloadData];
Hope, it'll work. And, since you reload it at viewWillAppear, please sure that neither it allocate new times nor it's delegate/datasource assign again, if it is then, first time, do something like that:
_mainTableView.delegate = nil;
_mainTableView.delegate = self;//similarly, for datasource...
And, you need to explicitly call your viewWillAppear(I suppose you're already doing this.)
Please let me know in any concern.
Thanks.
Thank you for the input, I finally got it sorted.
Instead of calling the [_mainTableView reloadData] I had to call the fetchmethod again.
if (_managedObjectContext == nil)
{
_managedObjectContext = [(AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSLog(#"After _managedObjectContext: %#", _managedObjectContext);
}
[self setupFetchedResultsController];

reloadData doesn't call cellforrowatindexpath

Maybe it's a similar beginning, but it's true.
first of all sorry if this isn't formatted correctly, first time doing this. I've been using stackoverflow to find help for a long time now and it's been very helpful (thank you all), but this is the first time I've posted a question of my own. This question has been asked many times, but when I call [self.tableView reloadTable] the methods numberOfSectionsInTableView and numberOfRowsInSection are called but not cellForRowAtIndexPath.
Every answer I've seen when searching has been a variation of:
The tableView is nil
numberOfRowsInSection is 0
tableView's delegate/data source not set. None of these are the case for me so I'm wondering what else could be wrong.
But I'm not sure 4. calling reloadTable on the wrong uiTableView. Or it's about some other false.
Now my APP is similar to dropbox,
first when we log into it, we get a file list(include directories) in the TableView.also, I added a toolbar in the bottom of the view by [self.navigationController.view addSubview:toolBar], when I touch the button item "refresh", it calls [self.tableView reloadData] and works well.
Second when we select a directory we will get a new file list table which is pushViewController by self.navigationController, but this time when we touch the "refresh", the statement [self.tableView reloadData] calls numberOfSections, numberOfRows, not cellForRowAtIndexPath
Any ideas as to why cellForRow's not being called the Second time? Thanks in advance.
FileListViewController.h
#interface FileListViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>
FileListViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (isDir) {
FileListViewController *fileListViewController = [[FileListViewController alloc] init];
[self.navigationController pushViewController:fileListViewController animated:YES];
}
}
- (void)refresh
{
[Utilities refresh];//Utilities is my custom class.
[self viewDidLoad];
[self.tableView reloadData];
}
My return number of section and row in table view is not 0.
When I added NSLog(#"Calling reloadData on %#", self.tableView); into "refresh":
- (void)refresh
{
[Utilities refresh];//Utilities is my custom class.
[self viewDidLoad];
NSLog(#"Calling reloadData on %#", self.tableView);
[self.tableView reloadData];
}
Then it returns Calling reloadData on ; contentOffset: {0, 0}>. Delegate: FileListViewController, DataSource: FileListViewController
You should not manually call [self viewDidLoad]. This method is designed to be overridden, and is automatically called. For more information, please read this documentation.

tableview won't update after adding objects to an array

I have a tableview inside a popover in my main view which is a web browser. Whenever the user visits a web page I want it to add the page to a list of recently visited websites. I have the code set up to add the URL as a string to the array that is the data source for the table view. The table view only shows the first site visited and won't show anything past that. However I know the sites are being added to the array because the array shows the Sites using NSLog statements after being added. However they still won't show up in the table. Can anyone help me?
EDIT:
- (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 [recentlyVisitedUrls count];
}
Also make sure you are returning the correct length of your array from – tableView:numberOfRowsInSection:
Try
[tableView reloadTable];
after you add the new data.
If you wan't animated updating, you can call:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO]
If you need animation, it will be better read: Table View Programming Guide for iOS, you need Batch insert… part.
If you have a large table, [tableView reloadData] is probably not ideal. It'll also will reset your view to the beginning of the table, which may or may not be desirable. You might try something like this:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:_model.recordCount - 1 inSection:0];
[_tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
BTW, _model is the data delegate class for the table in the example.
Also, make sure the data delegate updates it's total count correctly before you insert, or your app will crash on the insertRowsAtIndexPaths.

UITableViewController canceling Edit mode animation when calling [table reloadData] inside (void)setEditing

I'm having a little problem:
i made my setEditing method:
- (void)setEditing:(BOOL)editing animated:(BOOL)animate {
[super setEditing:editing animated:animate];
[mainTableView reloadData];
}
i'm using the reloadData to call: cellForRowAtIndexPath, and then, if the table is in edit mode, i'll change the appearance of my cell (hiding some labels, for example);
The problem is when i call [mainTableView reloadData] the Edit animation (the red circle slides from left to right and my cell slides to the right) doesn't exist. If don't call it, everything works ok, but i can't customize my cell, since cellForRowAtIndexPath is not called again.
Any suggestion to make it work ??
Thanks!
Maybe you will try to update your table with [tableView beginUpdates] and [tableView endUpdates]? Do you need to reload all the cells or only some of them?
EDIT: Here's the code for reloading all the cells:
[tableView beginUpdates];
NSMutableArray *updatedPaths = [NSMutableArray array];
for (NSNumber *row in yourArray) {
NSIndexPath *updatedPath = [NSIndexPath indexPathForRow:[row intValue] inSection:0];
[updatedPaths addObject:updatedPath];
}
[tableView reloadRowsAtIndexPaths:updatedPaths withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
yourArray is NSArray instance where you store your cell.textLabel values or something like that...

Is it possible to refresh a single UITableViewCell in a UITableView?

I have a custom UITableView using UITableViewCells.
Each UITableViewCell has 2 buttons. Clicking these buttons will change an image in a UIImageView within the cell.
Is it possible to refresh each cell separately to display the new image?
Any help is appreciated.
Once you have the indexPath of your cell, you can do something like:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPathOfYourCell, nil] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
In Xcode 4.6 and higher:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:#[indexPathOfYourCell] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
You can set whatever your like as animation effect, of course.
I tried just calling -[UITableView cellForRowAtIndexPath:], but that didn't work. But, the following works for me for example. I alloc and release the NSArray for tight memory management.
- (void)reloadRow0Section0 {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
[indexPaths release];
}
Swift:
func updateCell(path:Int){
let indexPath = NSIndexPath(forRow: path, inSection: 1)
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
tableView.endUpdates()
}
reloadRowsAtIndexPaths: is fine, but still will force UITableViewDelegate methods to fire.
The simplest approach I can imagine is:
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
[self configureCell:cell forIndexPath:indexPath];
It's important to invoke your configureCell: implementation on main thread, as it wont work on non-UI thread (the same story with reloadData/reloadRowsAtIndexPaths:). Sometimes it might be helpful to add:
dispatch_async(dispatch_get_main_queue(), ^
{
[self configureCell:cell forIndexPath:indexPath];
});
It's also worth to avoid work that would be done outside of the currently visible view:
BOOL cellIsVisible = [[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] != NSNotFound;
if (cellIsVisible)
{
....
}
If you are using custom TableViewCells, the generic
[self.tableView reloadData];
does not effectively answer this question unless you leave the current view and come back. Neither does the first answer.
To successfully reload your first table view cell without switching views, use the following code:
//For iOS 5 and later
- (void)reloadTopCell {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
NSArray *indexPaths = [[NSArray alloc] initWithObjects:indexPath, nil];
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
}
Insert the following refresh method which calls to the above method so you can custom reload only the top cell (or the entire table view if you wish):
- (void)refresh:(UIRefreshControl *)refreshControl {
//call to the method which will perform the function
[self reloadTopCell];
//finish refreshing
[refreshControl endRefreshing];
}
Now that you have that sorted, inside of your viewDidLoad add the following:
//refresh table view
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:#selector(refresh:) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:refreshControl];
You now have a custom refresh table feature that will reload the top cell. To reload the entire table, add the
[self.tableView reloadData]; to your new refresh method.
If you wish to reload the data every time you switch views, implement the method:
//ensure that it reloads the table view data when switching to this view
- (void) viewWillAppear:(BOOL)animated {
[self.tableView reloadData];
}
Swift 3 :
tableView.beginUpdates()
tableView.reloadRows(at: [indexPath], with: .automatic)
tableView.endUpdates()
Here is a UITableView extension with Swift 5:
import UIKit
extension UITableView
{
func updateRow(row: Int, section: Int = 0)
{
let indexPath = IndexPath(row: row, section: section)
self.beginUpdates()
self.reloadRows(at: [indexPath], with: .automatic)
self.endUpdates()
}
}
Call with
self.tableView.updateRow(row: 1)
Just to update these answers slightly with the new literal syntax in iOS 6--you can use Paths = #[indexPath] for a single object, or Paths = #[indexPath1, indexPath2,...] for multiple objects.
Personally, I've found the literal syntax for arrays and dictionaries to be immensely useful and big time savers. It's just easier to read, for one thing. And it removes the need for a nil at the end of any multi-object list, which has always been a personal bugaboo. We all have our windmills to tilt with, yes? ;-)
Just thought I'd throw this into the mix. Hope it helps.
I need the upgrade cell but I want close the keyboard.
If I use
let indexPath = NSIndexPath(forRow: path, inSection: 1)
tableView.beginUpdates()
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic) //try other animations
tableView.endUpdates()
the keyboard disappear