I've been searching for a really long time but I found no answer for my question(s).
In my app I have a segmented control with two buttons.
When I toggle between those buttons I do:
Show a loading screen as a subview
do an url request to get the content to show in my tableview
fill my dataArray for my TableView with the new data
call reload data
remove loading screen subview.
In most cases everything works fine, BUT..
Sometimes, really not often, the table view "crashes", after this 5 steps. It means. The view only show one or two cells. And when I scroll to top or bottom I only scroll into white. In my current solution I can't reproduce this error on my iPhone(IOS6), only in simulator(IOS7). I think it has something to do with scrolling while changing the data of the table view. It only occurs while scrolling and pressing the segmented control button shortly after started scrolling, but only sometimes. But it could have another reason for sure..
My Question is, what could cause the table view to layout wrong (only displaying some cells correctly and scrolling into white), any Idea? And how can I recover/redraw the whole tableview after this happened? Please help..
I read a lot about [tableview beginUpdates],[tableview endUpdates] and insertRows, but I think this is not the right solution in this case. Or tell me if I'm wrong.
Here is the main code snipped for steps 2-4. If another part of code could help, maybe the cellForRowIndexPath, let me know.
NSMutableArray *newResults = [[NSMutableArray alloc] initWithArray:[self getResultsForRequest:url]];
[resultsLock lock];
results = newResults; //results is the data source for my tableView
[resultsLock unlock];
[self.tableView reloadData];
Thanks to all responders.
Related
This is a very rare occurring bug from hell,
I have an infinite scroll controller that displays products, 2 in each row. Rarely, something affects the controller and causes items to vanish, when I tap the empty area where the item should be, it works as expected and directs the user to the item details controller. When I back out back to the list, sometimes the cell shows its content, and others get hidden.
Sometimes it just a couple of items missing, sometimes there are so many missing items that makes the list appear empty, like only 1 or 2 cells are visible per screen height.
An even stranger situation is, when I scroll really fast to the end and stretch the screen really fast out of the visible area, and there are no more items to load, the visible items can jump from left to right.
Please see these two videos.
https://www.dropbox.com/s/jibflcouz1ena8n/missingProductImages.mov?dl=0
https://www.dropbox.com/s/uz13fzorypnp38t/again.mov?dl=0
I could send code but I didn't want to clutter this place with full length code, let me know if you want to see a specific section of the code please. Maybe someone could have an idea of what might be going on by looking at the vids.
What's probably going on here is a state problem with your collection view cells. The code assigning model values to the cell's views would be of use here. But absent any actual information, the first thing to review would be the cell's prepareForReuse implementation:
Does it call super?
Does it clear out all current values?
Does it cancel any pending asynchronous operations?
Are fetches and cancellations correctly matched?
Next, check if there's any essential configuration in the cell's init/initWithCoder methods -- those are only called on first creation, not on reuse.
Those are the normal pitfalls of UICollectionView cell handling. If they don't suggest the problem, please post the cell code.
It looks like your cells are not being reused correctly.
Can you check that you have set the same reuseIdentifier for your cell in Interface Builder that you are assigning in your code?
Update: Attached image to show where to set the identifier in the storyboard/xib
Update: added layout solution
Another problem could be due to the layout bounds of your collectionViewCell. When you load your cells they bounds are not calculated until they have been added to your collectionView and rendered. This can cause the elements in your cell to layout with the wrong values. This happens commonly with async image frameworks as they cache a resized version of the image for performance. When you cell loads, the cached image is loaded at the wrong the wrong size.
Add the following code to your collectionViewCell:
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
self.contentView.frame = bounds;
[self setHighlighted:NO];
}
In the image below you can see a 2 appearing to the right of my UITableViewCell's accessory buttons. This only appears when I am using section headers (which is what I'm currently adding to my existing UITableView. If I fetch the data with sectionNameKeyPath:nil then the 2 doesn't appear.
My guess is that this 2 is appearing instead of the scrollIndicator. The 2 always remains in the center of the UITableView. When I don't use sections I see the scrollIndicator as expected. Does anyone know how to fix this?
Edit:
This shows that the floating 2 is a part of the scroll indicator.
hahah, that's great :) Butt! i think a way to find out where it's coming from is using the Debug View Hierarchy. Run your app and once you see the two in your table view:
once xcode has loaded the view from the Simulator, look for the two and click on it. at the top you'll see where this object is located.
Then i would try to back track on how it was added to this view. maybe it's part of a cell? etc.
I hope this helped getting closer to the answer :)
Well I finally found the problem. My superclass had the following code:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
return [self.fetchedResultsController sectionIndexTitles];
}
I must have picked up that code from an example somewhere when I setup my superclass for UITableViewController. In this case I don't want index titles, just the scroll indicator, so I removed that method.
I have regular UITableView with UISearchDisplayController in Navigation Controller. SizeToFit works on viewDidLoad normally, without any problems. But when i enter search a write some letters, it returns me items, that OK but size of tableview fails.
It is scrolling well, from the bottom to the top but when i reach last item, it stops in middle (it looks like 1 or 2 cells are missing but they are not) & HorizontalScrollIndicator also reach just the middle of tableview.
Any advice ?
It's possible that after you've provided some search parameters and manipulated your data source, you are missing a call for
[self.tableView reloadData];
Hard to tell without the code, but the tableView may be attempting to display rows that should not exist anymore - causing an error in cellForRowAtIndexPath
I've got a UITableView, each cell has an image and two labels, as you can see on the first picture
So I am trying ti use self-sizing cells and everything is great, except 2 things:
1) First and Second cell don't show content properly, but after I scroll down and then return to them everything is ok. I tried to use [tableview reloadData] in viewDidAppear, but it doesn't help. Watch the labels at first they don't fit. You can watch it on this video https://www.youtube.com/watch?v=I9DGBl1c5vg
Look at the labels on the first cell.
2) It's a tough one. I'm scrolling the table and everything is great, but the problem happens, when I select the row. It's pushing me to detail view, but when I press "back" and return to master view, the tableview jumps,so I'm coming back not to the selected row, also if I scroll the table it doesn't scroll smooth, but jumps. Here are the links for two videos, first one shows that scroll is smooth https://www.youtube.com/watch?v=9wAICcZwfO4 if i don't go to detail view, and the second shows the jumping problem https://www.youtube.com/watch?v=fRcQ3Za1wDM .
It's absolutely sure connected with self sizing cells, because if I don't use it, none of this problem happens.
Okay, I solved both of the problems.
Question 1
I've added these two lines
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath before return cell
Question 2
The solution appeared to be very simple. I've just needed to implement viewWillDissapear and reload data in it, so the code looks like this
- (void)viewWillDisappear:(BOOL)animated;{
[super viewWillDisappear:animated];
[self.tableView reloadData];
}
Solution for me was simple, if it doesn't work for someone, here I found some useful links.
1) UITableView layout messing up on push segue and return. (iOS 8, Xcode beta 5, Swift)
2) http://useyourloaf.com/blog/2014/08/07/self-sizing-table-view-cells.html
Unfortunately I believe both of the questions that you ask about are IOS bugs.
Question (1)
A easy fix is suggested by this blog.
When the table view is first displayed, you may find some of the cells are not sized properly. But when you scroll the table view, the new cells are displayed with correct row height. To workaround this issue, you can force a reload after the view appears:
Simply add the following to your viewDidAppear method. I have tested it and it works very well.
[self.tableView reloadData];
Question (2)
This second question is a duplicate of this following question:
IOS 8 UITableView self-sizing cells jump/shift visually when a new view controller is pushed
A workaround is suggested by the author of the question himself, which seems okay. However, I have not tried out this one yet.
Okay, I solved it by caching my cell heights in sizeThatFits, and returning that value for estimated cell heights within the delegate. Works beautifully.
Feel free to head over to that question for other proposed solutions.
I'm building a dictionary app, and one of the features is that you can "drill down" into a definition. You look up a word, there's a word in the definition you don't understand, so you tap that word and the app shows you the definition for that word, if available. This is pretty standard for iOS dictionary apps on the App Store, if anyone's familiar.
One feature is that I am going to have a bar that shows each word as you drill down, so you get a sort of "chain" of words across this horizontal bar. The idea is you can tap on the words in the chain to navigate forwards and backwards through your chain of words.
To represent this chain I am using a UICollectionView, with a subclassed UICollectionViewController. Since it's essentially a "grid" with a single row, this made sense to me. I'm using a storyboard, so I simply embedded my custom controller into the main view, pass events back and forth between the master controller and this custom collection controller. Pretty simple.
Now, let's say the user taps many different words, so you get the "chain" of UICollectionViewCells growing across the bar from left to right until you hit the edge. Since UICollectionView is based on/has a UIScrollView in it, this shouldn't be a problem. My concept is that, if the number of items to be displayed exceeds the width of the view, the CollectionView would expand the contentView and place items off the right edge of the view port, and I could then programmatically scroll the view to show the newly added item.
Here's the code that I use to do this (edited). It's a method that I call in my subclassed UICollectionViewController:
- (void)reloadDataWithAnimation
{
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:model.data.count - 1 inSection:0]
atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
}];
}
This is more or less what I'd normally do with a UITableView: tell it to reload its data after I have changed the model. It didn't quite work at first until I found a question on SO that covered the use of performBatchUpdates, and I had trouble doing the scrollToItemAtIndexPath until I realized it needed to go into the completion block.
Now, here's the funky part: everything works fine before the items fill up the whole view. The first time an item would go beyond the boundaries, the CollectionView places the item below the last item in the row. This looks really strange because the view is only one row tall, so you can kinda half-see the item parked below the last one in the row, mostly obscured. No scrolling occurs.
At this point, if you scroll the CollectionView back and forth, the item reconfigures itself and moves into the correct position. Or, if you add another item, they align correctly and the view scrolls as intended. Successive additions work just fine. However, if you scroll back to the left and then add another item, it briefly appears underneath the last currently visible item in the viewport, then the view scrolls off to the far right and as it scrolls the misplaced item jumps up into its proper position.
Although I began posting this question as I could find nothing on Stack Overflow, in the course of writing my question, the Similar Question sidebar updated and I found similar questions, and eventually an answer.
Similar question: UICollectionView cell layout is out of the collection view's bounds
Apparently this issue is known to Apple.
Here is the solution linked to in the above question: https://stackoverflow.com/a/13389461/700471
The code that Nick Snyder posted solved the problem for me perfectly.
Edit: Additionally, in the end I subclassed UICollectionViewLayout, bypassing FlowLayout, and made my own layout with this tutorial.