I am using a UICollectionView in my app with gesture recognizers on the individual cells which allow the user to "slide open" the cell to reveal more data underneath.
The problem is, I am reloading the data in the CollectionView very often; as the app receives updates once every 3 seconds or so. This results in unwanted behavior with the collectionview cells being reused while a cell is in the process of being slid.
The user will start to slide a cell, the app will receive an update, reloadData, and a different cell will start receiving the gesture instead, and begin sliding.
I have tried disabling the app's updates while the slide is occurring, but that caused other complications within the app, so I am wondering if there is a way to disable the cell reuse, (I will only have 20 cells max, so I don't think there would be a large drop in performance).
Thank you!
Why don't you use a flag like needsReload and set it, if new data is available. After a slide you check for that flag and reload the collectionView, if needed? Is this not working?
If you don't want cell reusing, just use a default scrollView and put all your views in it!?
Disabling reuse is simple. Just don't use the dequeueReusableCell method.
Instead just alloc, init your cells. I would be careful of the performance and memory implications of doing so though...
Related
So here's the description of the loop my app keeps falling on:
There is a UITableView containing ReactiveTableViewCell's (but I think RX part doesn't really matter here, so let's pretend these are UITableViewCell). Each cell embeds a UITextField upon an expandable/collapsable UIView (that allows me to show any error message related to the textfield) - when there is no error to show, this subview is collapsed.
The thing is, when UITableView gets scrolled and makes reuse of an "errored" cell, the subview of this cell is still expanded. As PrepareForReuse() method is made to reset cell state before a reuse, I thought it would be the right place to collapse the subview, and indeed it does... until the app falls into a loop, resizing top-screen and bottom-screen same cell forever.
How do you think I could fix this issue? Maybe is there a way to increase cell reuse tolerance so UITableView won't reuse a cell as soon as it disappeared from screen? Maybe shall I have a try with a resize-lock while list is being scrolled, but it will always leave some margin for error so it's not the fix I'm looking for.
Thanks for your help.
EDIT :
Well, it seems like the RX part was not so clueless. The IObservable I was subscribing to, aiming to show the error message, was a ReplaySubject. It appears that looping was happening on there due to this little guy, refreshing the UITableView (through TV.BeginUpdates/TV.EndUpdates) endlessly. So by now I assume ReplaySubject and cell-reuse won't work well altogether, since a simple replacement with a BehaviorSubject fixed the issue.
I am implementing a chat app using UICollectionView. Initially I fetch only 100 messages. As the user scrolls, I fetch some more messages and then reload the collection view. To maintain the scroll position I set the content offset but scrolling gets stopped. How to maintain the scrolling speed after reloading the UICollectionView so user doesn't feel jerk?
You could try to use the prefetchDataSource that was introduced in iOS10.
UICollectionView Prefetch Data Source in iOS 10?
There're several approaches to handle this.
You don't use reloadData() but rather insertItemsAtIndexPaths:, that way you don't have rebuild the whole table and only build the items you need.
You load additional data when use hits a specific point your collection view. In a willDisplayCell method you can check if indexPath of a cell is getting close to the last index in your data source and load additional rows. In the moment user will scroll to the last item, all the stuff will be already there so you don't have worry.
In my experience the best way is to use both of this approaches combined. Because in general using reloadData() every now and then could be very resourceful depending on your cell layouts.
I'd like to loop over loaded cells of an UICollectionView and highlight (by calling a cell method) a particular cell based on its model.
I can easily loop over visible cells, with collectionView.visibleCells, but I don't know how to reach prefetched cells.
Of course, disabling cell prefetching solves the problem, but I lose all its benefits.
Using a prefetchDataSource won't solve the problem, because the boolean that controls the cell's highlight state is not correctly set at the time of prefetching.
I might use the prefetchDataSource to keep track of loaded cells, but from what I read in the documentation, you don't have the actual cells at that point.
Should I just disable cell prefetching or is there a better way?
Something easy like collectionView.visibleCells would be great.
Thanks in advance.
I have a UITableView-based in-game shop.
Every cell has a "BUY" button which is mostly enabled and can be switched to "BOUGHT" if the item is a one-time purchase or can be disabled if there are not enough money.
Right now what I do is calling reloadData every time buy button is being pressed in order to update visible cells and the current cell itself. (I have to update all cells, because after purchase it is possible that there wont be enough money for visible item cells).
But it causes weird animation glitches, like when I click on one cell's buy button and animation finishes on another one.
I think this happens due to reusability of cells. So what I want to know is how to reload data in the whole table view without harming native animation.
The only thing I can think of is not to use reusable cells and cache them all, but I dont think this is a good programming practice.
First, make sure that your view layer and model layer are separate. There should be some non-view object that knows about each item; we'll call it Item.
Now, create an ItemCell (you probably have one already). That's your reusable cell. Hand it the Item. It should configure itself based on the data in there.
Use KVO, delegation, or notifications to let the cell observe its item. When the Item changes its status, the cell should update its own button.
When your cell is reused, you'll pass a new item to it. It should stop observing the previous one, and start observing the new one (and of course reconfigure itself to match the current status).
By separating the views (which are reusable and transitory) from the model (which is stable and long-lived), you get the performance benefits of cell reuse with correct animations and no need to call reloadData.
You could have a reloadCell method in the cell class and loop through the table's visibleCells and update their UI that way. That way they are not recreated (or re-used), they just have their relevant UI pieces that could have changed due to the new data updated.
I don't want cells to have to be generated when they come on screen for the first time. I also don't want cells that have gone off screen to have to be regenerated when they come back on the screen.
How can I have all the cells generated on loading the UICollectionView and stay that way as I scroll up and down?
You could manage your own list of cells (pre-create them based on the datasource, create any new ones as the datasource updates, and return the appropriate cell for the indexPath desired instead of dequeuing a cell inside cellForItemAtIndexPath) but as a general rule, that's a bad idea. You may have some specific case where cell configuration performance is poor, but the answer is usually "improve cell configuration" and rarely "keep everything in memory".
Speculating: If you're thinking of doing this in order to preserve state or cache some information in the cell, that's the wrong place to put it. The cell is presentation; keep that info in the datasource element so that whatever needs to be represented can be applied to whatever cell is being used right now.