When is UITableView finished updating? - iphone

My problem seems quite simple but I have failed to find a solution here or elsewhere.
I have a UITableView as a subclass in one of my UIViews. When the application finishes the last selected table cell is saved to NSUserDefaults and when the aplication restarts I want to set the seleced cell as it was before. However, this causes problems when I do it too early as the number of sections are unknown, i.e. the table hasn't loaded its data yet. So I decided to set it in the function numberOfRowsInSection, which works but I am sure is not the correct place to do this.
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
int iNofRows = 0; //Default
// It is not great doing this here but....
if(bSetDefaultSelection == YES)
{
bSetDefaultSelection = NO; // Stop recursion
**NSIndexPath* indexPath = [NSIndexPath indexPathForRow:(NSUInteger)l last_sel_row inSection:(NSUInteger)0];
[self selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];**
}
return iNofRows;
}

I think the place you're looking for is
- (void)viewDidAppear:(BOOL)animated;
// Called when the view has been fully transitioned onto the screen. Default does nothing
(See UIViewController for more information)
I've just debugged my app and that method is called after the one you've mentioned:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
In your case you'd have to write something like:
- (void)viewDidAppear:(BOOL)animated{
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:(NSUInteger)l last_sel_row inSection:(NSUInteger)0];
[self selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
}
Cheers!

Hey thanks for the reply. I thought nobody answered so much appreciate the effort. The solution with '(void)viewDidAppear:(BOOL)animate' only works with UITableViewController but I am dealing with UITableView.
But I decided to post a notification in my main controller that triggers the table to select and that works fine.
Thanks again.

Related

Clearing TableView contents

Can any one help me by providing code for how to clear all the table view cell contents.
The tableview when a button is pressed gets reloaded but does not get cleared
Thanks
Rakesh
For clearing a tableView, you just remove all objects from the array that is populating your table and you reload the tableView after that.
[myArray removeAllObjects];
[self.tableView reloadData];
Set a bool tableIsEmpty and set the number of rows in the tableview to either 0 (table is empty) or the arrays count according to this BOOl in
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
Of cousre you have to set tableIsEmpty = YES, when the button is pressed and to NO again when theres data loaded.
Then call
[self.tableView reloadData];
Not tested but should work shouldnt it?
You can just add one variable as flag before reloading the table.
makeEmpty = YES;
[tableview reloadData];
makeEmpty = NO;
Then in the tableview delegate method
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(makeEmpty)
return 0;
}

UITableView -> numberOfRowsInSection:(NSInteger)section returns wrong value

My 2nd time today... But here are so many good developers...
Hi,
I have some troubles with my tableView... If the view will appear my table reloads its data, but it doesn't update the numbersOfRowsInSection...
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"COUNTER: %i",[content count]);
return [content count];
}
The log says the first time I load the page the right value. But if I add an object and reload the data, this function isn't calling.
Is there anyone who know the solution?
Thanks,
mavrick3.
EDIT:
Heres how I call [table reloadData]
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ([content count] != 0) {
self.content = [[[[NSArray alloc] initWithContentsOfFile:[FileManager filePath]] objectAtIndex:row_] objectForKey:#"faecher"];
[table reloadData];
NSLog(#"----%#",content);
}
}
And yes, the dataSource and delegate are connected and they are both implemented in my header.
If you call reloadData on a UITableview object and you're it's dataSource then this method should be called called.
Are you sure that you have assigned your table view to your property (i.e. dragged it across in interface builder?)
I suspect that you have only made your controller the dataSource of your table view (hence the first time it loads it gets the value). After that your calls to reloadData won't work because the property in your view controller is still nil.
You can test this by putting an NSLog just before you call reloadData - if it outputs nil then you've not connected it.
NSLog(#"%#", myTable);
[myTable reloadData];
any compiler warnings?
Is "table" actually an instance of UITableView?

reloadRowsAtIndexPaths:withRowAnimation: crashes my app

I got a strange problem with my UITableView: I use reloadRowsAtIndexPaths:withRowAnimation: to reload some specific rows, but the app crashes with an seemingly unrelated exception: NSInternalInconsistencyException - Attempt to delete more rows than exist in section.
My code looks like follows:
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
When I replace that reloadRowsAtIndexPaths:withRowAnimation: message with a simple reloadData, it works perfectly.
Any ideas?
The problem is that you probably changed the number of items of your UITableView's data source. For example, you have added or removed some elements from/to the array or dictionary used in your implementation of the UITableViewDataSource protocol.
In that case, when you call reloadData, your UITableView is completely reloaded including the number of sections and the number of rows.
But when you call reloadRowsAtIndexPaths:withRowAnimation: these parameters are not reloaded. That causes the next problem: when you are trying to reload some cell, the UITableView checks the size of the datasource and sees that it has been changed. That results in a crash. This method can be used only when you want to reload the content view of the cell (for example, label has changed or you want to change its size).
Now if you want to remove/add cells from/to a UITableView you should use next approach:
Inform the UITableView that its size will be changed by calling method beginUpdates.
Inform about inserting new row(s) using method - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation.
Inform about removing row(s) using method - (void)deleteRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation.
Inform the UITableView that its size has been changed by calling the method endUpdates.
I think the following code might work:
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
I had this problem which was being caused by a block calling reloadRowsAtIndexPaths:withRowAnimation: and a parallel thread calling reloadData.
The crash was due to reloadRowsAtIndexPaths:withRowAnimation finding an empty table even though I'd sanity checked numberOfRowsInSection & numberOfSections.
I took the attitude that I don't really care if it causes an exception. A visual corruption I could live with as a user of the App than have the whole app crash out.
Here's my solution to this which I'm happy to share and would welcome constructive criticism. If there's a better solution I'm keen to hear it?
- (void) safeCellUpdate: (NSUInteger) section withRow : (NSUInteger) row {
// It's important to invoke reloadRowsAtIndexPaths implementation on main thread, as it wont work on non-UI thread
dispatch_async(dispatch_get_main_queue(), ^{
NSUInteger lastSection = [self.tableView numberOfSections];
if (lastSection == 0) {
return;
}
lastSection -= 1;
if (section > lastSection) {
return;
}
NSUInteger lastRowNumber = [self.tableView numberOfRowsInSection:section];
if (lastRowNumber == 0) {
return;
}
lastRowNumber -= 1;
if (row > lastRowNumber) {
return;
}
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
#try {
if ([[self.tableView indexPathsForVisibleRows] indexOfObject:indexPath] == NSNotFound) {
// Cells not visible can be ignored
return;
}
[self.tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
#catch ( NSException *e ) {
// Don't really care if it doesn't work.
// It's just to refresh the view and if an exception occurs it's most likely that that is what's happening in parallel.
// Nothing needs done
return;
}
});
}
After many try, I found "reloadRowsAtIndexPaths" can be only used in certain places if only change the cell content not insert or delete cells. Not any place can use it, even you wrap it in
[self beginUpdates];
//reloadRowsAtIndexPaths
[self endUpdates];
The places I found that can use it are:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- (IBAction) unwindToMealList: (UIStoryboardSegue *) sender
Any try from other places like call it from "viewDidLoad" or "viewDidAppear", either will not take effect (For the cell already loaded I mean, reload will not take effect) or cause exception.
So try to use "reloadRowsAtIndexPaths" only in those places.
You should check cell visibility before reload. Here is Swift 3 code:
let indexPath = IndexPath(row: offset, section: 0)
let isVisible = tableView.indexPathsForVisibleRows?.contains{$0 == indexPath}
if let v = isVisible, v == true {
tableView.reloadRows(at: [indexPath], with: .automatic)
}
I had the same issue. In my case; it was happening only if another view controller pop/pushed over existing table view controller and then[self.tableView reloadRowsAtIndexPaths] function is called.
reloadRowsAtIndexPaths call was hiding/showing different rows in a table view which is having over 30, visually complex, rows. As i try to fix the issue i found that if i slightly scroll the table view app wasn't crashing. Also it wasn't crashing if i don't hide a cell (by returning 0 as height)
To resolve the issue, i simply changed the "(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath" function and returned at least 0.01 as row height.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
return rowModel.height + 0.01; // Add 0.01 to work around the crash issue.
}
it solved the issue for me.
THIS IS OLD. DO NOT USE.
I just bumped into this issue when I was calling reloadRowsAtIndexPaths... in order to change the cell to an editing cell containing a UITextField. The error told me I was deleting all of the rows in the table. To solve the problem, I removed:
[self.tableView beginUpdates];
NSArray *reloadIndexPath = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:count inSection:section]];
[self.tableView reloadRowsAtIndexPaths:reloadIndexPath withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
and replaced it with
[self.tableView reloadData];
The app crashes because you have made some changes to your tableView. Either you have added or deleted some rows to the tableView. Hence when the view controller asks your model controller class for data, there is a mismatch in the indexPaths. Since the indexPaths have changed after modification.
So either you simply remove the call
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
or replace it with
[self.tableView reloadData];
Calling reloadData checks your number of sections, number of rows in each section and then reloads the whole thing.
If data count changes completely, then use reloadData else, there is three functions to do it.
When data count changes we use insertRows / deleteRows and when data count still the same use reloadRows.
Important! don't forget call beginUpdates and endUpdates between insertRows/deleteRows/reloadRows calls.

problem in reloading tableview

HI all
i am using
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[tableview reloadData];////not working
}
but my table is not reloading.but when i put
[tableview reloadData];
in viewdidload, my data didnt show up.
BUt on rerunning the app, whole data shown up...
i m confused ,what is happeneing here.plz suggest me a proper way to reload table.
Try
[self.tableView reloadData];
check that you have set the delegates properly
In
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [datas count];
}
Make sure that you update the mutable array "datas" with the values.Because only with reference to this array count table cells are created.
All the best.

How do I select a UITableViewCell by default?

I have created a UITableView and would like a specific UITableViewCell to appear selected (blue) when the view is loaded.
-(void)viewWillAppear:(BOOL)animated {
// assuming you had the table view wired to IBOutlet myTableView
// and that you wanted to select the first item in the first section
[myTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
animated:NO
scrollPosition:UITableViewScrollPositionTop];
}
I'm using this technique to select one of two UITableViewCells so the users knows which cell a UIDatePicker below the table view it will effect. This technique is used by Apple in the calendar app when you create a new event and set the dates.
Be judicious using this method, as selecting the row in this way is something Apple suggests against doing to show a "chosen" state.
Instead, consider setting the cell's accessoryType property to something like UITableViewCellAccessoryCheckmark.
You should put it in viewWillAppear.
[myTableView selectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
animated:NO
scrollPosition:0];
If you try to select it in cellForRowAtIndexPath:, then it will not take the required style.
Definitely watch out. I'm sure you have a good reason, but look closely at the Human Interface Guidelines document Apple provides. Apps get rejected for not unselecting table rows. I'd encourage you to find the appropriate section of the HIG and see Apple offers any suggestions.
Use this code to select cell by default in table view, indexPath can be vary according to your need
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:0 inSection:0];
[theTableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];
}
Use the UITableViewCell method
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
Info here.
Sometimes, when you're not in a UIViewController, you have no viewWillAppear, and sometimes, you created your UITableView programmatically.
The easy solution is to implement this delegate method:
- (void)tableView:(UITableView *)tableView
willDisplayCell:(UITableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.selectedIndex == indexPath.row) {
cell.selected = YES;
}
}
It's does not work in the cellForRowAtIndexPath because the cell is not yet displayed. and the setSelected method is called just when this one is displayed.