仅加载 UITableView 中的可见单元格

Posted

技术标签:

【中文标题】仅加载 UITableView 中的可见单元格【英文标题】:Load only visible cells in UITableView 【发布时间】:2014-10-14 04:11:27 【问题描述】:

所以我有一个应用程序,它从数据库中读取记录,并基本上用数据库中的信息填写 UITableView。其中一些信息包括一张图片,它来自我拥有的在线服务器。一切正常,但程序有点慢,滚动有点迟钝/跳跃,因为它一次带来所有图像,而不是在我滚动时带来它们。有没有办法改变它,以便在我滚动它时带来接下来的几个可见记录?

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath 

    static NSString *CellIdentifier = @"VersionCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

    if (cell == nil) 
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                      reuseIdentifier:CellIdentifier];
    

    STSneakerInfo *info = [_versionInfo objectAtIndex:indexPath.row];

    cell.textLabel.font = [UIFont boldSystemFontOfSize:14.1];
    [[cell textLabel] setNumberOfLines:2];

    cell.textLabel.text = [[_uniqueBrand stringByAppendingString:@" "] stringByAppendingString: info.version];

    cell.detailTextLabel.textColor = [UIColor grayColor];
    cell.detailTextLabel.font = [UIFont boldSystemFontOfSize:14.1];
    cell.detailTextLabel.text = info.initialReleaseDate;

    NSString *brandVersion = [[_uniqueBrand stringByAppendingString:@" "] stringByAppendingString:info.version];
    NSString *underscoredBrandVersion = [brandVersion stringByReplacingOccurrencesOfString:@" " withString:@"_"];
    NSString *underscoredBrandName = [_uniqueBrand stringByReplacingOccurrencesOfString:@" " withString:@"_"];

    NSData *imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: ([[[[[@"http://www.abc/img/" stringByAppendingString:underscoredBrandName] stringByAppendingString:@"/"] stringByAppendingString:underscoredBrandVersion] stringByAppendingString:@"/"] stringByAppendingString:@"default.jpg"])]];
    cell.imageView.image = [UIImage imageWithData: imageData];

    return cell;

【问题讨论】:

您可以使用SDWebImage 进行异步图像下载。请显示cellForRowAtIndexPath:的一些代码。 @Chinttu-RoxeN-Ramani 我在上面添加了一些代码 查看我和 WenchenHuang 的答案。但我更喜欢 SDWebImage 是好的库。它将处理缓存。 @Chinttu-RoxeN-Ramani - 现在它的工作速度非常快,这很好,但我遇到了一个小问题。在这个应用程序中,我有几个不同的 tableViews,并且选择性不同的表格单元格将您移动到不同的 tableViews。所以假设我的类别是水果、蔬菜和奶酪,我点击奶酪,它会用正确的图片有效地加载所有类型的奶酪,但是如果我点击一种奶酪,比如说黄色奶酪,它会带来到一张所有照片都是第一张照片的桌子上。知道是什么原因造成的吗?这有意义吗? 你的意思是你必须用动画全视图显示奶酪类别的图像。 【参考方案1】:

您可以使用 (https://github.com/rs/SDWebImage) 异步下载图像。简单快捷。

我更喜欢这个库,因为它会处理你的缓存。 写在下面的代码

[cell.imageView sd_setImageWithURL: [NSURL URLWithString: ([[[[[@"http://www.abc/img/" stringByAppendingString:underscoredBrandName] stringByAppendingString:@"/"] stringByAppendingString:underscoredBrandVersion] stringByAppendingString:@"/"] stringByAppendingString:@"default.jpg"])]];

您也可以按照上面的wenchenHuang回答在后台线程中下载图像。使用下面的代码。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString: ([[[[[@"http://www.abc/img/" stringByAppendingString:underscoredBrandName] stringByAppendingString:@"/"] stringByAppendingString:underscoredBrandVersion] stringByAppendingString:@"/"] stringByAppendingString:@"default.jpg"])];
        if (data)
        
            UIImage *img = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^
                if (img)
                    cell.imageView.image = img;
            );
        

    );

也许这会对你有所帮助。

【讨论】:

SDWeb 令人钦佩,但 DLImageLoader 真的很难被击败。它非常坚固***.com/a/19115912/294884【参考方案2】:

UITableView 类永远不会加载单元格,直到它们即将出现在屏幕上。 建议你使用GCD下载图片背景,完成后注意UI变化。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
       //Download images
        dispatch_async(dispatch_get_main_queue(), ^
            //Notice UI to change
        );
);

【讨论】:

【参考方案3】:

这是一个完整的、真实的 DLImageLoader 示例

https://github.com/AndreyLunevich/DLImageLoader-ios/tree/master/DLImageLoader

DLImageLoader 编写得非常好,经常维护,超轻量级,并且可以正确处理浏览

它很难被击败,并被用于拥有大量用户的许多应用中。

它确实是一个维护得非常好的库 - 最重要的是,新的 Swift 版本是 Swift 编程的巅峰之作,它是如何做到这一点的模型。

PFObject *aFacebookUser = [self.fbFriends objectAtIndex:thisRow];
NSString *facebookImageURL = [NSString stringWithFormat:
    @"http://graph.facebook.com/%@/picture?type=large",
    [aFacebookUser objectForKey:@"id"] ];

__weak UIImageView *loadMe = self.cellImage;
[DLImageLoader loadImageFromURL:facebookImageURL
   completed:^(NSError *error, NSData *imgData)
    
    if ( loadMe == nil ) return;

    if (error == nil)
        
        UIImage *image = [UIImage imageWithData:imgData];
        image = [image ourImageScaler];
        loadMe.image = image;
        
    else
        
        // an error when loading the image from the net
        
    ];

另一个现实世界的例子,

-(UICollectionViewCell *)collectionView:(UICollectionView *)cv
         cellForItemAtIndexPath:(NSIndexPath *)indexPath
    
    NSInteger thisRow = indexPath.row;
    BooksCell *cell;
    cell = [cv dequeueReusableCellWithReuseIdentifier:
              @"CellBooksNormal" forIndexPath:indexPath];

    cell.layer.shouldRasterize = YES;
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;

    // set text items...
    cell.title = @"blah;

    // set image items using DLImageLoader...

    __weak UIBookView *loadMe = cell.anImage;
    [DLImageLoader loadImageFromURL:imUrl
       completed:^(NSError *error, NSData *imgData)
        
        [loadMe use:[UIImage imageWithData:imgData]];
        ];

    return cell;
    

【讨论】:

【参考方案4】:

滚动缓慢的原因是您正在主线程上下载图像。

NSData *imageData = [[NSData alloc] initWithContentsOfURL:

在主线程上运行的那段代码将进行网络调用并开始从服务器下载内容。执行会在那里停止,直到完成。这意味着在加载图像之前,您将无法再向下滚动。

有很多解决方法。然而,所有人的逻辑都是一样的。在单独的线程中下载图像并在完成后加载它。

如果您在项目中使用 AFNetworking,则可以在您的 UIImageView 对象上使用 setImageWithURL:。您需要包含UIImageView+AFNetworking.h。它有一个内置的缓存机制,它将缓存为该会话下载的图像。

【讨论】:

以上是关于仅加载 UITableView 中的可见单元格的主要内容,如果未能解决你的问题,请参考以下文章

在单个 UIScrollview 中使用多个 UITableViews,如何仅加载可见单元格的单元格数据

延迟加载 - UITableview 可见单元格不显示图像

重新加载 UITableView 数据而不是可见单元格

如何检测 UITableView 中有多少个单元格可见

TableView 仅加载可见单元格(12 个部分表视图中的前 4 个部分)

UITableView 删除并重新加载单元格