I have special content that I load in my CollectionViewCells from a server. This content takes a few seconds to finish loading. My issue is that once a cell is loaded, and I start scrolling my collection view, it is removed once it is not visible and needs to load again from the server, since collectionView(_:cellForItemAt:) is called again. In apple docs I see this message:
I found that note here:
https://developer.apple.com/reference/uikit/uicollectionview/1771771-isprefetchingenabled
I am not sure if I am on the correct track here, but I thought this function may help me "hack" the system to load all the cells and never deque them, so I achieve the result of scrolling my collection view back and forth and not have cells reload.
Is there a way to do that using the function collectionView(_:willDisplay:forItemAt:)? Is it possible to do it otherwise? any help is appreciated.
Related
I'm trying to load a table view with cells that contain images downloaded off the internet. I'd like to only perform the download operation on cells that are currently visible instead of downloading every image as the user scrolls down quickly.
I found the indexPathsForVisibleRows method and that should fit my needs nicely but I need a way to figure out when the table view is no longer scrolling. My idea is to use the indexPathsForVisibleRows when the table view isn't scrolling so that all of the images currently on screen are loaded without unnecessarily loading images.
Are there any methods that I can override or notifications to subscribe to that will alert me when the table view is no longer scrolling?
Thanks!
Take a look at the methods listed here:
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html
If your view controller is the delegate of the UITableView, these will also be fired for it, as the UITableView is a subclass of UIScrollView.
Particularly, pay attention to: scrollViewDidEndDecelerating. This is the one I used to do pretty much what you're asking.
I am implementing a UIScrollView which behaves mostly like a UITableView, a bit more advanced with that.. but most of the API used are the same signature.. cellForRowAtIndexPath.. etc. First before people start storming why not just use a UITableView, let me just say that I can't. The reasons are fairly complex, but that is a decision been made.
The issue is now I am implementing infinite scrolling, basically when I scroll down and I am at 65% of the full contentHeight I am doing an async request to the backend to fetch more data and adding it to the data source and then calling reloadData. The issue is that if I am calling reloadData while the user is scrolling, it doesn't provide a very smooth scrolling experience. So what is the best way to tackle this? Also I noticed that reloadData basically refreshes the entire table view (in this case my scroll view). In my table view cell I am animating a UIImage to fade in. So when reloadData is called, the image that is already presented is being faded in again, which is kind of annoying.
How do I avoid such things?
Any tips and tricks?
In case you're still working on this, check out PSTCollectionView. It works exactly like UICollection view but supports backwards of iOS 4.3.
Its difficult to answer without knowing why you need to create a custom view similar to the tableview. If you have a developer account you might want to check the new iOS 6 view based on tableview. Not sure if I can talk more about it as it is under NDA.
For the UIImage fading, how about flagging each UIImage as displayed and then do a check when reloading the data or recalling the fade statement. Only fade the images that are not flagged as already presented?
In new iOS 6.0 there is new controllers call UIContainer view,its similar to UITableview but we can also set more then one column with that.
delegate methods for that controllers are almost same as in UITableview.you can use that controller if you have similar requirements.
I have a UITableView that contains several cells and some of them (the ones for files that are still uploading) have both an UIActivityIndicator and an UIProgressView. The ones for files that are finished use a different icon (instead of the activity indicator) and hide the progressview.
This table is using a NSFetchedResultsController as data source, so I get the updates on the data model and update the content.
Everything works just fine. The problem, however, is performance. Every time I call reloadData my UIActivityIndicators flicker, and it's not very smooth. Although I'm caching from the nib file, reloadData will have to calculate the new progress % for the ProgressView and I don't do anything with the ActivityIndicator other than hiding it if upload is complete.
Anybody ever tried something similar? Is there a workaround?
I was thinking about having an array of my progressview references and use that instead of calling reloadData.. not sure if this is the correct approach.
Thanks,
Fernando
When you call reloadData on the UITableView, all the cells of the table view are completely refreshed, re-assembled and redrawn. All the old ones are thrown away. This means that all the subviews of the UITableViewCells are removed and re-created too (including your UIActivityIndicator and UIProgressView). The refresh causes these views to flicker, or perhaps jump back to their start state. As there is no way of setting the frame of a UIActivityIndicator, your suggestion of restoring some progress value simply isn't possible.
Instead, perhaps you should try and engineer your "refresh" to not require a complete refresh of the table? For example, if you want to change the text of a UITextField within the view, you could simply access this text field and set the text property (no refresh is required). Or, if you want to hide your progress indicators, you could go into the appropriate object instances and set their property. You should design your app so that this is possible. Making changes this way avoids having to reload cells from scratch.
Besides the benefit of fixing your problem, using this method of updating, you should also see a large performance increase. reloadData is a very costly method to use and should be only used if it is absolutely necessary to really re-create the entire UITableView from scratch.
Hope this helps. :)
I've got another problem my my UITableView: I dynamically load "Questions" from a XML File and show them inside cells of my UITableView, where the user can also answer them. The Problem is: if you scroll down, and then scroll up again, the answers that you typed before, just disappear. I've also noticed that UITableView calls the method tableView:cellForRowAtIndexPath: again, and that is exacty my problem, cause this method loads the questions from the XML File again so that all the answers that the User has typed get lost.
How can I keep all the cells in memory, and stop doing lazy loading of the cells?
I would appreciate any suggestions.
Thanks!
Store and preserve retrieved data in an NSMutableArray and hook this up as a data source to the table view.
I'm curious just how expensive in as far as resources go is UITableView's reloadData? I have an app which will make roughly 10 subsequent HTTP requests, and as it gets data / preps, it reloads the tableView. As the data set grows larger and larger, it's becoming very sluggish. I'm trying to figure out if it's because of the amount of times I'm reloading the tableView or because of how I'm grabbing/parsing the data.
What's the best practice in this case?
From UITableView.h:
- (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
"This is cheap."
implement your table view methods well and it'll be no big deal to call this function all the time.
On a side note, you should try to use the appropriate methods to animate adding and removing rows if you are thinking of using reloadData for that.
The best practice is to have your implementation of cellForRowAtIndexPath: do as little work as possible. In fact, it really shouldn't be doing any work except populating the UITableViewCell instance with the data it needs to display.
You should be using cached UITableViewCells so you don't have to allocate a new cell each time. If you can do your parsing and such in a separate thread and make the parsed data, ready to present, accessible to cellForRowAtIndexPath:, you shouldn't have any performance problems.
You didn't say if you were using a custom UITableViewCell subclass, but if you are, deep view hierarchies can also present a performance problem, since each view in the hierarchy gets drawn. The flatter you can make UITableViewCells, the better.
Hope that gets you moving in the right direction.
Best thing to do is profile your app to see where it is slow.
That said, if your table cells are all the same height, then I think
reloadData
only has to call
cellForRowAtIndexPath
for cells that are visible on screen.
Table view reload expense is:
Figuring out how many sections and
rows per sections you have
getting row heights.
Row heights in particular are figured out for all elements of the table, anytime you call reload data.
The remaining expense is cellForRowAtIndexPath, which is usually not too bad because it only is called for as many rows as are on the screen. It can be bad when scrolling if you do not reuse cells like you are supposed to.
The key for you is probably, to ask yourself what triggers the HTML load and possibly move that into a background thread.
Boot To The Head is correct.
I'm doing a progressive one-by-one article list update in Instapaper, and I call -reloadData on each completed download. Sounds similar to what you're doing. It doesn't result in any noticeable performance slowdowns.