I got an UITableView
which is filled with an unknown amount of rows. Each row contains (for example 3) images and the application gathers this information from a webservice.
For the UITableView
I implemented infinite scrolling. Whenever the table almost reaches the end of the current amount of rows, I initiate a call to the webservice, to fetch the next 50 rows of data. I do this in the scrollViewDidScroll
method which is called by the UITableView
.
- (void) scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat actualPosition = scrollView.contentOffset.y;
float bottomOffset = 450;
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)
bottomOffset = 1000;
CGFloat contentHeight = scrollView.contentSize.height - bottomOffset;
if (actualPosition >= contentHeight && !_loading && !_cantLoadMore)
{
self.loading = YES;
_currentPage++;
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject:[NSNumber numberWithInt:_currentPage] forKey:@"page"];
[dict setObject:[_category objectForKey:@"ID"] forKey:@"category"];
[self performSelectorInBackground:@selector(getWallpapersInBackground:) withObject:dict];
}
}
The images in the rows of the UITableView
are lazy loaded. Whenever a row is visible, the images are loaded in a separate thread and the rows are updated once an image is fully downloaded. The principle I use for lazy loading, is the same as Apple suggests in their documentation. The image is also added to a local NSDictionary
, so I can fetch it when the row scrolls out of the screen and back in (and the row is recreated).
Because the amount of pictures in a single view can go up to 2000 - 3000, I also cache the images to disk and clear out the images from the NSDictionary
when they are further than X rows away. When the user scrolls down and up again the following happens:
- New rows are displayed
- Lazy loading method is called, which checks if the image is present on disk or that it should download it.
- When the image is downloaded or fetched from disk, it performs a codeblock, which displays the image in the row. Images downloaded from the internet, are also cached to disk.
UIImage
is added to NSDictionary
for faster caching of images that need to be within reach.
- Images which are in rows, 15 rows or further from the visible rows are removed from the
NSDictionary
, because of memory problems (too many UIImage
objects in the NSDictionary
cause out-of-memory errors).
When the UITableView almost reaches the end, the following occurs:
- UITableView almost reaches end of currently loaded rows
- Call to webservice, with loads of new rows (50)
- The new rows are added to an array, which is used for the
numberOfItemsInSection
method.
- A
reloadData
is called to make sure the UITableView
populates with the extra new rows.
- New rows that contain images, performs the steps mentioned above to lazy load the images.
So, the problem I have is when I am adding new records from the webservice. When I call a reloadData
on the UITableView
some images are loading from disk again and some hickups occur while scrolling.
I am looking for a solution for this. I tried using insertItemsAtIndexPaths
with the amount of new rows, to add them to the UITableView
, but this makes my lazy load method already download the images (because somehow all the cells are created at that time, even when they are not visible, checking if cell is visible during creation delivers unexpected results, images not loading, cells look weird, etc).
So, what I essentially am looking for is a solution for an infinite scrolling UITableView, which lazy loads images from the web/disk and is as smooth as the photo application. Since images are all loaded in separate threads, I don't understand why scrolling isn't as smooth as a baby's skin.
See Question&Answers more detail:
os