UITableView cells are unloaded too early after reordering - ios

I've recently built in reordering into my UITableView but there's a nasty bug I'm experiencing after reordering the cells. The bug only occurs after a cell has been reordered: When scrolling the table view up, the cells visible at the bottom of the screen sometimes simply disappear while scrolling. It seems as if the cells are unloaded too early. This only happens when scrolling up. When scrolling down the bug doesn't exist. The cells that randomly disappear also re-appear when scrolling down once their empty space leaves the screen. Here's a screenshot of this issue:
I'm pretty sure that my data source isn't the problem because:
When reordering a cell my data source updates as well
I've checked the table view with Spark Inspector and the missing cells aren't simply hidden or empty but they just don't exist, there is no cell at all where the empty spaces are.
After scrolling around the cells re-appear, the cells randomly appear and disappear
It must be some bug or issue in UITableView, but I may also be wrong with that assumption. Maybe somebody has already faced this problem and can help me out now ;) I'm waiting for your answers :)
Edit:
I just checked the -tableView:didEndDisplayingCell:forRowAtIndexPath: delegate method and the cells are really unloaded normally and that method is called, even though the cells are still visible on the screen!
Edit (2):
I now know that the issue only occurs when my table view has a header view. It doesn't matter if I use the default header or a custom one, but whenever I use a header view I also get the bug. When I don't use a header it works just fine. Thats really strange
Note: I'm testing this on iOS 6.1.2

Related

UITableView cells disappearing, wrong cell passed to didEndDisplayingCell

I'm seeing another case of UITableView cells disappearing unexpectedly when scrolling, but none of the similar questions & answers here I've seen really fit what I'm seeing:
I scroll down until my top cell is removed and tableView:didEndDisplayingCell:forRowAtIndexPath: is called for it, then scroll back up until it's shown again. During the scroll up, the tableview is trying to remove the cells that were shown while scrolling down, however its actually removing the wrong cells.
As I'm scrolling up, tableView:didEndDisplayingCell:forRowAtIndexPath: is getting called with the correct index path, one it should be removing, but a cell that corresponds to a different index path. The cell and index path passed to the didEndDisplayingCell don't match.
This is in a small modification of the XLForm example project from https://github.com/xmartlabs/XLForm in which I've added a custom cell. What's weird is that if I make my custom cell the same height as the table's normal height (44) then this doesn't happen. Only when my cell is taller (64, with this value returned from tableView:heightForRowAtIndexPath: and tableView:estimatedHeightForRowAtIndexPath:).
I'm seeing this happen when running in the simulator, iOS versions 8.4 and 9.2.
I haven't been able to figure this out. I don't think I have any of the bugs that have caused others to have disappearing cell syndrome, but even if I do, I don't see how or why the tableview would be calling didEndDisplayingCell with cell and index path that don't match. Does anyone else have a clue what's happening?

UITableViewController scrollViewDidScroll: not called during cell removal

I have a tableView whose content is smaller than the screen, so its not scrolling.
I'm reloading one of the sections when changing to editing mode, which causes the tableView to add rows.
When I now scroll down and then deactivate the editing mode, the tableView removes the redundant cells again and scrolls to top.
During this scroll operation I'm not getting any scrollView delegate calls.
For details, please check my implementation: GISTViewController.m
Well, after reading your question a few times, it looks like our issues aren't the same.
I believe your issue is because scrollViewDidScroll: is not called during some animations. You should see this answer here, though unaccepted (maybe because they imply user interaction is the only way to trigger it), it also contains a path to this answer about getting scrolling events during automated animations which may be of help.

When reloading sections, footer is not displayed in UIViewCollectionView

Basically I have a button on the footer of a section that shows more cells in that particular section. However, I have a problem when I perform :
[self.friendsCollectionView reloadSections:sectionSet];
The footer seems to disappear after the reload. Also, when you scroll down a bit, it will re-appear. I am also using flowlayouts to manage my cells.
Also, I am on landscape mode so I am assuming after the increase, the flow layouts are not updated. Since collectionView viewForSupplementaryElementOfKind:atIndexPath is not even called.
Anyone have a solution?
Try calling invalidateLayout on your layout before calling reloadSections:. That will cause the layout to be re-applied after the sections are redrawn, which should cause your footer to redraw.

UITableViewController weird behavior after popping a view controller

My UITableView has a bunch of reusable cells, and when I tap on one of them, it takes me to another view controller (via push segue) showing the details of that cell (let's say it's an item, so it would show details about an item - name, price, image, etc...). When I pop that view controller (by tapping on the back button), the UITableView has a strange behavior:
a) if it's scrolled all the way to the bottom, it will scroll automatically tad up (around 50 points), leaving the last cell barely visible, so I have to scroll back down again. My cell all have 60 points for height.
b) the scrollbar always shows and then disappears, indicating that something is moving that UITableView (although if not scrolled to the bottom, the content will not move automatically).
This happens in multiple UITableView's I have in my app. I am not forcing a reload of the table view in viewWillAppear, so I don't understand what is happening. My content is static after loading from the server (unless the user changes it, and then the reload is executed). But simply showing details of an item and popping that VC doesn't change anything in the table view.
Edit: Okay, I've figured what the problem is: I'm hiding a UIToolbar when pushing that segue. If I keep it always visible (which I don't want), it still shows the scrollbars animating when popping in my table view but doesn't scroll the table view if on the last few rows.
Add the following to viewDidLoad.
self.automaticallyAdjustsScrollViewInsets = NO;
This solved my problem of table view moving down after navigating back to view controller.
I managed to fix the first issue. It seems like the tableview is not taking into account the 44 points of the UIToolbar.
Save the tableview offset in prepareForSegue: (save it in a CGPoint property)
self.tableViewScrollOffset = self.tableView.contentOffset;
Then, in viewWillAppear:, check if it has been modified. If so, restore it.
if(self.tableView.contentOffset.y != self.tableViewScrollOffset.y) {
[self.tableView setContentOffset:self.tableViewScrollOffset];
self.tableViewScrollOffset = CGPointZero;
}
This behavior is indeed a bug in iOS 8.x.
All answers given so far can not really solve the issue. The issue is, that iOS forgets (or doesn't) consider the previously calculated cell sizes, when a table is being redrawn for instance when the view is being pushed.
One approach to solve this can be found here: UITableView layout messing up on push segue and return. (iOS 8, Xcode beta 5, Swift) (so this question is even a duplicate to this one).
However, the solution provided there is overkill and there are certain situations why this caching will fail (for instance a UIContentSizeCategoryDidChangeNotification is not regarded)
But there is a quite simpler solution even though it is odd:
If you are using a manual performSequeWithIdentifier in didSelectRowAtIndexPath, just add a [self.tableView reloadData] just before.
If you are using a IB seque from the cell, just add [self.tableView reloadData] in your prepareForSeque code.
The reason, why this solves the issue is, that this will force iOS to re-estimate the visible cells and so it no longer scrolls the content to another location. Fortunately, tableView reloadData doesn't cost too much overhead here as only the visible cells will be re-estimated.
Just a hunch, have you got a rogue scrollToRowAtIndexPath:atScrollPosition:animated hanging around?
I was also facing this issue. I managed to find it out. The reason in my case is tableview header height was calculating based text and text height was negative due to which tableview was shifting down even though the contentinset and scrollinset are zero.
This was only occurring for first time. Next time it is calculating correct. One weired thing i found is that when Class A (having tableview) have pushed another Class B from init. When keyboard from Class B is opened viewDidLoad of Class A is called. and before Class B is unloaded from navigation controller. Tableview is reloaded for Class A.
Setting the automaticallyAdjustsScrollViewInsets as suggested above did not work neither did caching and setting the tableViewScrollOffset work.
Hence came up with an workaround which worked like a charm for me.
The workaround was to add an Dummy UIView which has height of 1px and width of 320px and place it between the "Top Layout Guide" and the UITableView. This view's background could be set to clear so that it is invisible.
Now using Autolayouts, fix the Dummy View's top to the Top. Now set the tableview's top constraint with respect to Dummy View. Found that this resolved the issue of the tableview's misplacement.
Screenshot of the Dummy View along with the autolayout constraints have been provided for easy reference. The Dummy View has been set to a larger height and red background colour for illustration purpose only.

Issues regarding dynamic resizing of label and row heights (iOS)

Context:
Building an app that populates a table that takes in data from a asyc json dump.
The cells are of a custom class (I defined). The main label in the cell can be very long.
It is "placed" in storyboard within a prototype cell but customized via code (pretty standard stuff).
Labels are resized in cellForRowAtIndexPath and rows are resized via heightForRowAtIndexPath -- rows are resized by forcing a call to cellForRowAtIndex like Massimo's answer here
So per the question at hand - I've noticed some interesting (bad) things that happen.
First issue: When the table loads, the rows and labels are dynamically resized correctly! Great! However, when I scroll down and then scroll back up, the label heights will be incorrect -- (for example) the first row was correct at loading. Then when I scroll down and then scroll back up to see it again, it will be truncated. Specifically, the row size will be fine but the label height will change and become truncated to 2 lines only. Wondering if this is because I did both storyboard and coding to customize the cell. Anybody see this before?
Second issue: When I scroll down, while the rows are sized correctly (large), the labels are short (truncated.) Wondering if it's some reverse of the above "potential answer".
"potential answer" is that the rows are all calculated and stored "up front" so that scrolling down/then back up doesn't affect it. However, when cells go "out of view" and are dequeued then when they re-viewed (scroll down/then back up) it will rely on the storyboard.(inappropriately?)
All three of your issues are symptomatic of returning the wrong height in heightForRowAtIndexPath. In my data model classes I have a calculateHeight method that I call in heightForRowAtIndexPath. The model also caches the answer so it doesn't have to recalculate it after the first call. The cell class uses the model's calculated height to layout its subviews.
"ANSWERED" by deleting the prototype cell from the storyboard and making them fully in code, the issue went away. The fundamental workings are still not understood (ie. the interactions between storyboard vs. code when cells are put queued and then viewed again)

Resources