Show Table View Cell when WebView is loaded - iphone

I have a UIWebView in my Grouped Table View, and because the heightfor one cell is variable I want the function heightForRowAtIndexPath to wait for the webViewDidFinish befor it is calculated. How can I do that ?

Haven't tried, but what if you do [_myTable reloadData]; at the end of your webViewDidFinish? That should reload the table information.
Or you could try a BOOL with a while loop?
Set the boolStillLoading to true before sending the request, then when it comes back then set it to false
viewDidLoad...
while(boolStillLoading){
sleep(.2);
}
It's not pretty or probably the most efficient way, but it will keep the table from loading while you execute stuff before it.
Would love to see other approaches though...

You cant stop calling heightForRowAtIndexPath explicitly, but you can make a tweak for this. after loadingweb view again call table reload data for height.
Use Web view delegate method for the same.
– webView:shouldStartLoadWithRequest:navigationType:
– webViewDidStartLoad:
– webViewDidFinishLoad:
– webView:didFailLoadWithError:
store variable value (for hieght) in webViewDidFinishLoad and then call tableview reload data. now in cellForRowAtIndex method use this variable for height.

Related

UITableView ReloadData not using dequeued cells

I am working on an iOS RSS reader app.
My app implements a UITableView with custom section headers:
UINib *sectionHeaderNib = [UINib nibWithNibName:#"HeadlineView" bundle:nil];
[self.newsTable registerNib:sectionHeaderNib forHeaderFooterViewReuseIdentifier:SectionHeaderViewIdentifier];
Every section header is used to display an article title.
I have an option to change between the "already seen" articles and the new articles.
Every time I switch between the options, the table views data array is changed so I need to call UITableView ReloadData:
[self.newsTable performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
when I call this method it takes a bit more than 1 second to load (which seems stuck) because it reloads all the section headers instead of using dequeued section headers.
when I just scroll the table view everything works fine and the dequeue is working properly.
Every time I initialise a section header I set up 3 gesture recognizers and that's what takes a long time. but if the section header is dequeued, the gesture recognizers are already set so it is fast.
this is the dequeue code:
NowsHeadlineHeaderView *sectionHeaderView = [self.newsTable dequeueReusableHeaderFooterViewWithIdentifier:SectionHeaderViewIdentifier];
I am not performing any other time consuming tasks in the cell/section loading.
Why is the tableview initialising the section header over and over again when I use reloadData and how can I fix this so it will be faster
Forcibly calling reloadData wipes the slate clean on dequeued cells/headers/etc. From the documentation:
Call this method (reloadData) to reload all the data that is used to
construct the table, including cells, section headers and footers,
index arrays, and so on. For efficiency, the table view redisplays
only those rows that are visible. It adjusts offsets if the table
shrinks as a result of the reload.
If what you are doing is adding or substracting cells or sections, try using insertRowsAtIndexPaths:withRowAnimation: and deleteRowsAtIndexPaths:withRowAnimation: instead.
I also suspect your NowsHeadlineHeaderView set up is doing something inefficient, you might want to look into that.

cellForRowAtIndexPath: not called

My app has two states: logged in and not logged in, and I have the following architecture (vastly simplified):
- ViewController A which contains a search box and a table view.
- ViewController B which is used for logging in the app.
The flow is the following:
- the user is not logged in;
- A is pushed on the stack. In viewWillAppear I check if the user is logged in and if yes, an async network request is being made and, once that is done, the table is loaded with the data from the network. However since the user is not logged in at this point, the table view is empty;
- the user taps on the search box; because he's not logged in, B is pushed (after a confirmation);
- he logs in successfully in B, then presses a button which pops B and shows A again;
- at this point in time, because he's logged in, from viewWillAppear I do the async request;
- when that is completed, I call reloadData on the table view.
What I notice is that numberOfRowsInSection: is called and it returns the correct result, however cellForRowAtIndexPath: is NOT called afterwards and the table remains empty.
I've checked and reloadData is called on the main thread.
Any idea what can it be? Cause it's driving me nuts!
Thanks,
S.
EDIT: Here's the async bit of code from viewWillAppear in A.
if ([User isLoggedIn]) {
[self.asyncRequest fetchDataWithCompletionHandler:^(id response, NSError *error) {
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if (error) {
[Utils displayError:error];
} else {
self.array = response;
self.isLoaded = YES;
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointMake(0.0f, 0.0f) animated:NO];
}
}];
}
I've checked that the async request completes successfully and that response contains the correct data (this is the array used to back the UITableView).
After reloadData, I've put a breakpoint in tableView:numberOfRowsInSection: and it stops there and it returns the correct number of elements in array. After that, however, the breakpoint in tableView:cellForRowAtIndexPath: is never hit.
One valid scenario for why numberOfRowsInSection would be called but cellForRowAtIndexPath would not be called is when the size or positioning of the table does not require any rows to be displayed.
For example, let's say you had a table that was 20 pixels high, but the header for the first section was 30 high and you returned nil for the header (or did not implement viewForHeaderInSection). In this case, no rows would be displayed and it would look like the table just isn't there.
I see you are using IB. The sizing of the table can be deceptive in IB as it is assuming header and footer sizes. I would log the frame for the table so you understand where it is when the appliction is run (versus where it appears in IB). I would also be sure to manually size and position the table's frame before calling reloadData. This will solve this valid case where cellForRowAtIndexPath is not called.
Check that the numberOfSectionsInTableView is not returning 0.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
I had the exact same issue and the problem was that I was trying to call reloadData: from another thread. The solution would be:
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
If you are using a different dataSource, as I was, make sure you are retaining the dataSource. Merely instantiating the class that will be the dataSource and assigning it via tableView.dataSource = myDataClass will not be sufficient as the dataSource property of a tableView is weak and will be released when viewDidLoad completes. All of the other methods were being called for me — even, surprisingly, heightForRowAtIndexPath — so this took me some time to debug.
If a Table View inside a view that conflicts something like Scrool View, it does not called. You should separate the views in your Storyboard or *.xib file.
// True
▼ View
► Table View
► Scrool View
► Constraints
// False
▼ View
► Scrool View
► Table View
► Constraints
// For others showing up on this questions via Google, etc.
// Check and make sure you've set the table view's data source and delegate.
self.tableView.dataSource = self;
self.tableView.delegate = self;
We had the same/similar issue. The code reached numberOfSections and numberOfRowsInSection (and it even returned values) but could not reach cellForRowAt. At the time, Table View in the Storyboard had only constraints for right side, left side and top, but not for bottom. Once we added constraint to the bottom, it worked like a charm.
So, check that you provide all needed constraints for the Table View.
If you are using auto layout like me and adding tableview to your view controller's view make sure you have added this line when you are allocating your table view.
tableView?.translatesAutoresizingMaskIntoConstraints = false
Silly mistake from my side.
Everyone keeps talking about height, but my TableView in a StackView with leading alignment ended up with 0 width.
Make sure to check if your TableView is correct size using Debug View Hierarchy.
I solved the problem because my Subview on which i added the UITableView was not allocated so it was returning nill and tableview was not calling cellForRowAtIndexPath but numberOfRowsInSection getting called
Wasted hours and then found out that my tableview was inside a stackview. As soon as I removed the stackview, it worked like a charm. For me it's Xcode 11.3 .
I am using a customer datasource and it was released. Because it is a weak reference of tableview.
This is embarrassing and perplexing, but here's my fix.
My code:
_scanResultTable.delegate = self;
_scanResultTable.dataSource = self; // self's lifecycle was fine, wasn't getting released
[_scanResultTable reloadData];
So the weird part is: the identifier _scanResultTable was never declared in my code, anywhere in the project. I have no idea how this compiled (and I recompiled several times).
My root cause was that I had linked my table output to scanResultTable in my ViewController, but was referring to it as _scanResultTable. Once I started using scanResultTable like I should've been, things cleared up. This makes me wonder if objective-c has something special about leading underscores in identifiers...
Edit: It does! Good lord I can't wait to never touch this language again.
In my case, I had the TableView inside a StackView. When I put it outside the StackView it worked.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Make sure self.data isn't nil!
// If it is, you'll always return 0 and therefore
// cellForRowAtIndexPath will never get called.
return [self.data count];
}
I'm using ReactiveCocoa. So I've created the model for table view. The data was prepared to be displayed, so numberOfRows and so on was called. But I haven't added the tableview as subview, thus cellForRowAtIndexPath was not called)))
This maybe too obvious but in my case i was deleting an element (Label) which was a reference to the top margin of my table programmatically, so it was not a problem with delegate/source but of the table having some problems with the content-size / height, this conflict created a weird behaviour, calling numberOfRowsInSection but not cellForRowAt indexPath
Are you sure that after the user logged in and B is popped the viewWillAppear method in A gets called in order to perform the refresh?
If you show B as a modal controller, when you dismiss it you won't have the viewWillAppear method called.
As far as I know, viewWillAppear/viewDidAppear (and other like it) are events generated by the UINavigationController in the case of navigation events (push/pop viewcontrollers).
So maybe that is why you eventually get your refresh when you leave A and return ... it all depends on the way to display the next viewcontroller.
Try to insert new rows manually instead of [self.tableView reloadData]:
[self.tableView beginUpdates];
for (int i = 0; i < responseArray.count; i++) {
_rowsNumber += 1;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
}
[self.tableView endUpdates];
In dataSource method return incremented int _rowsNumber:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _rowsNumber;
}
i solved same issue by checking tableViewCell identifier. Go To Attributes İnspector and look at identifier section. Probably is missing. So write cell identifier.
Same case here, but it was a mistake:
I included a Scrollview with 2 tablesViews inside a ViewController (design requirements), in the scrollview controller I created the ViewControllers (that contains the TableViews) programatically and I used a weak var to store it, bad idea because they were released at the end of viewDidLoad method.
If you don't see your tableview content, please, check if it was released.
My mistake was very brain-painful for me because all methods (delegate&datasource) were called except viewForCell...
I have same issue
i have use Table View inside the StackView and table view scroll disable and set height constrain but after that
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
Not working stop calling this method all Data Source and Delegate set properly.
if you have same issue than Solution is set Table View bottom , leading , trailing constrain
None of the answers here helped me.
I was using doing my constraints programmatically but forgot to write:
myTableView.translatesAutoresizingMaskIntoConstraints = false
Make sure your constraints are correct and none of them is removed at build time.

UITableView datasource method does not call in Device 3G iOS4.0

When I call this Code
[[self tableView]reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:kSectionShoppingList]] withRowAnimation:UITableViewRowAnimationNone];
HeightForRowAtIndexPath Calls
But in CellForRowAtIndexPath for section 3 row 0 does not call.
Looking for your suggestion.
and it is specific to Device 3g iOS4.0.1.
Is anyone earlier have faced same issue.
Is the cell you are reloading visible ?
Not sure about iOS4.0.1, don't have it installed to test, but on iOS5+, the cellForRowAtIndexPath is not called if the cell is not visible, just tried it in one of my apps.
The issue i have mentioned look like a bug in iOs4.0.1. anyway I have solved it by reloading whole table using reloadData method instead of reloading particular rows.
Make sure your are reloading sections and rows that are visible and corresponding the the right indices in your tableview. Also check that your tableView delegate and datasource are correctly set.
reloadData method as the following comment :
- (void)reloadData; // reloads everything from scratch. redisplays visible rows. because we only keep info about visible rows, this is cheap. will adjust offset if table shrinks
you may also have trouble reloading single rows if your table is mutating, then you should beginUpdate / endUpdate methods
- (void)beginUpdates; // allow multiple insert/delete of rows and sections to be animated simultaneously. Nestable
- (void)endUpdates; // only call insert/delete/reload calls or change the editing state inside an update block. otherwise things like row count, etc. may be invalid.

UITableView's indexPathsForVisibleRows incorrect?

When I check for a table's visible indexPaths with 'indexPathsForVisibleRows' during UIScrollViewDelegate's scrollViewDidScroll and scrollViewDidEndDragging, it seems to be accurate.
But sometimes just when scrolling and dragging is ending and 'cellForRowAtIndexPath' is invoked, the call to 'indexPathsForVisibleRows' returns 0. There are rows visible on-screen so I know it can't be 0. As soon as this happens, I can invoke UITableView::visibleCells and get a non-zero value.
Why does this discrepancy exist?
Did you tried calling methods in below sequence:
[MyTable visibleCells];
[MyTable indexPathsForVisibleRows];
There is a bug in iOS with indexPathsForVisibleRows. Use above two line code to get correct visible rows.
in swift, this works:
let viscells = tableView.visibleCells
let isThisCellVisible = (tableView.indexPathsForVisibleRows ?? []).contains(indexPath)
but this does not
_ = tableView.visibleCells
let isThisCellVisible = (tableView.indexPathsForVisibleRows ?? []).contains(indexPath)
visibleCells and NSFetchedResultsController
be careful how you access visibleCells. the UI will freeze indefinitely if you [attempt] to access the table view's visibleCells while they were in the process of being updated, which is not allowed.
e.g. how you use tableView.beginUpdates()/tableView.endUpdates(), or controllerWillChangeContent(_:)/controllerDidChangeContent(_:), etc
full debug message if this happens is:
[Assert] Attempted to access the table view's visibleCells while they were in the process of being updated, which is not allowed. Make a symbolic breakpoint at UITableViewAlertForVisibleCellsAccessDuringUpdate to catch this in the debugger and see what caused this to occur. Perhaps you are trying to ask the table view for the visible cells from inside a table view callback about a specific row?

How do I set a custom cell for non databound TableCells

I am happily able to set the styling of my tableviewcells using the cellForRowAtIndexPath delegate, but I want to set the background of all the nonpopulated cells which are still on the screen
hey, basically any cell which is part of your tableview belongs to a particular index and particular row
so incase you are not populating a particular section via data source - you can still get a reference to a cell in that indexPath by manually calling the cellForRowAtIndexPath delegate, and passing the section as well as row index
it returns you a cell. assign it to your private variable and edit it the way you want to.
Use the visibleCells method on your table view. Then do what you wish to the cells.
Alternately, you could call indexPathsForVisibleRows to get just the index paths. Then call cellForRowAtIndexPath: to get the cell corresponding to each index path.