UITableView与infite滚动和延迟加载 [英] UITableView with infite scrolling and lazy loading

查看:126
本文介绍了UITableView与infite滚动和延迟加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 UITableView ,它填充了未知数量的行。



对于 UITableView ,每行包含(例如3个)图片,应用程序从Web服务收集此信息。我实现了无限滚动。每当表几乎到达当前行数的结尾时,我启动对webservice的调用,以获取接下来的50行数据。我在 UITableView 调用的 scrollViewDidScroll 方法中执行此操作。

   - (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];
}
}

UITableView 被延迟加载。每当一行可见时,图像就被加载到一个单独的线程中,并且一旦图像被完全下载就更新行。我用于延迟加载的原则,与苹果在他们的文档中建议的一样。该图像也被添加到一个局部 NSDictionary ,所以当行滚出屏幕并返回(并重新创建行)时,我可以抓取它。



因为单个视图中的图片数量可以达到2000 - 3000,我还将图片缓存到磁盘并清除来自 NSDictionary 当它们超过X行。当用户向下滚动并向上滚动时,会发生以下情况:


  1. 显示新行


  2. 当图片从磁盘下载或提取时,它会执行一个代码块,显示图片是否存在于磁盘上,图像在行。

  3. UIImage 已添加到 NSDictionary
  4. 中删除​​行,15行或更远的可见行中的图片> NSDictionary ,因为内存问题(中的 UIImage 内存错误)。

当UITableView几乎到达结束时,会发生以下情况:


  1. UITableView几乎到达当前已加载行的末尾

  2. 调用web服务,加载新行(50)

  3. 新行添加到数组,用于 numberOfItemsInSection 方法。

  4. A <$调用c $ c> reloadData 以确保 UITableView 填充额外的新行。

  5. 包含图片的新行,执行上述步骤以延迟加载图片。

因此,我遇到的问题是从webservice添加新记录。当我调用 reloadData UITableView 一些图像从磁盘加载,一些hickups滚动时出现。 p>

我正在寻找一个解决方案。我尝试使用 insertItemsAtIndexPaths 与新行的数量,将它们添加到 UITableView ,但这使我的延迟加载方法已经下载了图像(因为不知何时所有的单元格在那时被创建,即使它们不可见,检查单元格在创建期间是否可见提供意外的结果,图像未加载,单元格看起来怪异等)。



因此,我本质上寻找的是一个无限滚动UITableView的解决方案,它懒惰加载来自web /磁盘的图像,并像照片应用程序一样光滑。由于图像都是以不同的线程加载的,我不明白为什么滚动不像宝宝的皮肤那样光滑。

解决方案

我不知道我是否完全理解你的问题,但这里有一些我遇到类似问题时所做的事情。




  • 我使用 -tableView:cellForRowAtIndexPath:作为从网络加载更多数据的提示。我选择了一个数字(在我的例子中为10),当 indexPath.row + 10> = self.data.count 加载更多数据。




    • 我需要调用 -tableView:cellForRowAtIndexPath:

    • 没有强制回调到 -scrollViewDidScroll:的紧缩循环。


  • 我将 UIImageView 子类化为一个可以异步加载我调用 URLImageView


    • -tableView:cellForRowAtIndexPath:,我为


    • 该作业导致了从磁碟载入或从网路载入的背景作业。操作可取消,因此我无法继续处理不再需要加载的图片。




我有一个有几百(但不是数千)图像的表视图。我一次只在屏幕上显示2或3个表格单元格。




  • 我使用 -refreshData :它像一个冠军。

  • 我甚至得到 URLImageView 淡入图像。这是一个非常好的效果。



我希望有帮助。


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:

  1. New rows are displayed
  2. Lazy loading method is called, which checks if the image is present on disk or that it should download it.
  3. 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.
  4. UIImage is added to NSDictionary for faster caching of images that need to be within reach.
  5. 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:

  1. UITableView almost reaches end of currently loaded rows
  2. Call to webservice, with loads of new rows (50)
  3. The new rows are added to an array, which is used for the numberOfItemsInSection method.
  4. A reloadData is called to make sure the UITableView populates with the extra new rows.
  5. 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.

解决方案

I'm not sure if I totally grok the fullness of your question, but here are some things that I did when confronted with a similar problem.

  • I used -tableView:cellForRowAtIndexPath: as my cue to load more data from the web. I picked a number (in my case 10), when indexPath.row + 10 >= self.data.count load more data.

    • I needed to call -tableView:cellForRowAtIndexPath: anyway.
    • I didn't force a callback into the tighter loop of -scrollViewDidScroll:.
  • I subclassed UIImageView with a class that would async load images which I called URLImageView.

    • In -tableView:cellForRowAtIndexPath:, I assigned a URL to the URLImageView instance.
    • That assignment caused a background operation that would either load from disk or load from the web.
    • The operation was cancelable, so I didn't keep working on an image that no longer needed loading.

I had a table view with hundreds (but not thousands) of images. I only had 2 or 3 table cells on the screen at once.

  • I used -refreshData: it worked like a champ.
  • I even got URLImageView to fade in the image. It was a very nice effect.

I hope that helps.

这篇关于UITableView与infite滚动和延迟加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆