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.
Related
My sport app keeps track of who is on and off the field, and for how long. I normally have 20-30 people to swap around, during training time. I have a timer to reload the visible cells of the collection view every second. The whole collection view reload can cost between 120-150ms.
The scrolling performance is good, however, sometimes the tapping to swap players does not respond. I think that is when the collection view is trying to reload the cells.
I can see there might a couple of ways:
Use UITableView, with each row to have 4 different elements.
Use UIScrollView, and preload all elements there. We used to use KKGridView library here, but it is way outdated. That is why we move to UICollectionView after 6-7 years
Have anyone had the same issue, and which way should provide the acceptable level of efficiency but not too complex to implement (to reduce the number of bugs)
Keep the record of the cell's index that need to update, then get the Cell from collection view, call method ask it to update itself, push the view update to the cell class, it wont mess with your collection view tap/drag...
Reload whole collectionView is only needed when whole dataSource change, yours is simply cell-by-cell update as I notice
I already found entries with that topic on this page and also a website that provides a tutorial for that problem. But nothing worked very well.
The tutorial sad I should double the height of my tableView so cells loaded earlier, but with a higher tableView I never reached the last cells.
My problem is, I use a tableView to display my apps mainpage. This mainPage shows every time a topic and if its necessary for that topic it shows for example a cell with a map, one with pictures and sometimes not. Problem now, if I trying to scroll to my view its always lagging because it loads a map or this pictures. And scrolling back again because the loaded cells already deleted. I used a tableView because of the possibility to switch celltypes(mapCell, pictureCell, textCell) on and off.
I understand this feature, because of memory issues but in my case its not that much and it would be better if all my cells be preloaded and stay in memory until I change the topic.
Is there a swifty way to told my tableView to have this behavior?
Thanks a lot and nice greetings
I would suggest a different approach. Set up your table view controller to install placeholder images in your cells, trigger an async download that you cache to disk, and then update the cell with it's downloaded content if it's still visible when the download is finished.
There are various third party frameworks that do all this housekeeping for you.
Declare a cell array.
Follow these steps whenever change in your topic.
Clear you array
Create and configure all cells add to your array.
Return these cells to datasource methods using row index. Don't use tableview dequeue method here.
I have to fill a TableView with lots of items (20.000 items frol sqlite) but I know that I will overload it.
Is there a way to load only the needed data when scolling ?
for example if I display 100 items when I scroll over 100 should I load 200 in the table or load only the items 101>200 ?
Also is it possible when returning the Cell content to fetch for EACH element in the embedded sqlite DB ?
Thanks
I have to fill a TableView with lots of items (20.000 items frol sqlite) but I know that I will overload it. Is there a way to load only the needed data when scrolling?
UITableView is designed specifically to load only the cells that are visible. You don't so much "fill" a table as you make the data available to the table via the table's data source. As the table scrolls, it asks its data source for additional cells, and it re-uses the cells that are no longer visible. This minimizes memory usage and maximizes speed. You don't need to do anything to achieve this other than implement the necessary table view data source and delegate methods in your view controller (or some other object).
Also is it possible when returning the Cell content to fetch for EACH element in the embedded sqlite DB ?
Sure, you can do that. Just implement your -tableView:cellForRowAtIndexPath: method to make the appropriate SQLite query for the requested cell.
This the default functionality of a UITableView, it only draws the necessary rows when they need to appear. This is why you have "reusable cells" because they keep getting reused. I think storing the 20,000 items should not be terrible memory overhead, so I would just try using the UITableView default functionality and you will be fine.
I would like to have my UITableView load 3 or 4 cells outside of the table so that any data to be shown there is already loaded when I scroll down.
I have some images, and data that must be downloaded before it can be shown in the cell.
This causes a visible delay before the images are loaded when scrolling.
I can manually trigger loading of this data by doing it in the UITableViewDataSource tableView:cellForRowAtIndexPath: method. I've done this before, but I'm curious if there's an easier way to do it.
Is there any way to expand the reusable cell pool, or adjust how the cells are loaded/recycled?
EDIT:
To clarify, I have lazy loading of images and data in place.
Everything works fine, I just wanted an easy solution to the "prefetching" problem.
Which can be solved in many ways that has nothing to do with the view itself. Right now you can easily see the images load as you scroll. I just wanted them to load right before they become visible.
You may be looking for an asynchronous table view that loads the data asynchronously.
Apple provides a sample app demonstrating this:
LazyTableImages
Of course, you could pre-cache the data and begin downloading data into your datasource before they scroll.
The general idea is that you are loading data into a datasource (that is separate from the UI), so you can do this at any time (and in the background). You can display temporary data or some type of loading image or spinner if the data isn't loaded yet.
If data of the cell will be loaded when cel becomes visible, you can programmatically scroll the table view by scrolling to the bottom cell and go back to the first cell without animation. Another way would be creating all the cells and placing them into array when your view controller is created, and feed the table from that array that contains already created cells. I think there is no way to extend the cell pool as you are asking. Hope this helps, Good Luck!
I have a UITableView that collects data from a database. What I would like to know is if there is some way I can iterate in the UITableView collection and check the values of the cell? The reason I ask is because I would like to update each cell based on the current value that it has (change font, size, color, etc.). I've seen in another SO post regarding this topic, but since the cells are already created and their values are changed it is a bit harder for me. I was thinking of iterating through the UITableView before I call reloadData, but any other suggestions are welcome.
You should not iterate over the cells of UITableView, because some of them (in fact, most of them) may not be present until you request them. UITableView aggressively recycles its cells, so if a cell is not visible, it is very likely that you would be creating it from scratch only to put it back into recycle queue moments later.
Changing your model and calling reloadData the way your post suggests would be the right solution. iOS will ensure that it runs the update in a smallest number of CPU cycles possible, so you do not need to worry about the cells that are already created. This is also the easiest approach in terms of your coding effort.
A table view is for displaying data. The properties of your table cells should only be written to, not read from. The appropriate way of handling this situation would be to update your underlying model objects -- the objects that you use to populate the table view -- as the data changes, and then reload the affected rows.
The issue you'll encounter is that UITableView reuses table cells. Once a table cell scrolls off the screen, it's quite likely that the table view will reuse the same cell to display a different row.
This means it's fundamentally not possible to iterate over the table cells. When you need to refresh a row because its data has changed, you should call reloadRowsAtIndexPaths:withRowAnimation: (or reloadData if all rows have changed) and if the row is visible on screen, UITableView will call your data source methods and give you an opportunity to configure the cell for display.