在cellForRowAtIndexPath处从CoreData加载图像会减慢滚动速度 [英] Loading image from CoreData at cellForRowAtIndexPath slows down scrolling

查看:79
本文介绍了在cellForRowAtIndexPath处从CoreData加载图像会减慢滚动速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用非常类似于iOS原生Photo应用程序的UITableView:它有很多行,每行有4个图像缩略图. (即,每个UITableViewCell具有4个UIImageViews)所有从Core Data加载的缩略图.

I am working on a UITableView that is very much like the iOS's native Photo app: it has many rows with 4 image thumbnails in each row. (i.e. each UITableViewCell has 4 UIImageViews) All thumbnails loaded from Core Data.

我已经多次修改了实现,可以看到性能方面的改进,但仍然无法像Photo应用程序一样流畅地滚动.

I have revised my implementation multiple times and I can see performance improvements, but it is still unable to scroll as smooth as the Photo app.

我需要有关如何正确缓存照片以获得最佳性能的建议.这是我尝试过的:

I need advise on how to properly cache the photos for best performance. This is what I tried:

1.我的第一次尝试(滚动时非常滞后)

  • 图像在CoreData中以Transformable类型存储.
  • 在cellForRow函数中,每个图像都是从CoreData上获取的 飞.
  • Images are stored with type Transformable in CoreData.
  • In cellForRow function, each image is fetched from CoreData on the fly.

2.第二次尝试(速度更快,但在滚动时仍会滞后)

  • 使用Binary Data类型存储图像,并在CoreData中选中外部存储"选项.
  • 在cellForRow函数中,每个图像首先从Core Data加载,然后存储到内存中的NSCache中,因此下一次cellForRow触发时,如果可用,我们将直接使用NSCache中的UIImage.

使用NSCache缓存从CoreData加载的图像后,滚动明显更快,但由于在NSCache中尚不可用时仍必须从CoreData加载图像,因此滚动有时仍会比较麻烦.

After using NSCache to cache images loaded from CoreData, scrolling is visibly faster but since images still have to be loaded from CoreData when it is not yet available in NSCache, scrolling will still be jerky from times to times.

因此,必须有一种更好的方法,我可以将所有图像预加载到内存中,但是由于可能存在大量或成排的图像,所以我根本不打算预加载图像.

So, there must be a better way, I could preload all the images into memory but since there might be large number or rows of images so I didnt plan to preload the images at all.

我还能怎么做才能更快地将图像加载到cellForRowAtIndexPath中?

What else can I do to load the image faster in cellForRowAtIndexPath?

推荐答案

为使滚动平滑而不管数据来自何处,您需要在单独的线程上获取数据,并且仅在拥有数据时才更新UI在记忆中. 大中央车站是您的理想之选.这是一个骨架,假设您有一个self.photos词典,其中包含对图像文件的文本引用.图片缩略图可能加载或未加载到实时词典中;可能在文件系统缓存中或可能不在文件缓存中;否则将从在线商店中获取.它可以使用Core Data,但平滑滚动的关键是您不必等待数据任何地方的来源.

To keep your scrolling smooth regardless of where your data comes from, you need to fetch your data on a separate thread and only update the UI when you have the data in memory. Grand Central Despatch is the way to go. Here's a skeleton which assume you have a self.photos dictionary with a text reference to an image file. The image thumbnail may or may not be loaded into a live dictionary; may or may not be in a filesystem cache; otherwise is fetched from an online store. It could use Core Data, but the key to smooth scrolling is that you don't wait around for the data wherever it comes from.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    static NSString *CellIdentifier = @"Photo Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    //identify the data you are after
    id photo = [self.photos objectAtIndex:indexPath.row];
        // Configure the cell based on photo id

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //move to an asynchronous thread to fetch your image data
            UIImage* thumbnail = //get thumbnail from photo id dictionary (fastest)
            if (!thumbnail) {    //if it's not in the dictionary
                thumbnail =      //get it from the cache  (slower)
                                 // update the dictionary
                if (!thumbnail) {   //if it's not in the cache
                  thumbnail =       //fetch it from the (online?) database (slowest)
                                    // update cache and dictionary
                    }
                }
            }
            if (thumbnail) {  
                dispatch_async(dispatch_get_main_queue(), ^{
                //return to the main thread to update the UI
                    if ([[tableView indexPathsForVisibleRows] containsObject:indexPath]) {
                    //check that the relevant data is still required
                        UITableViewCell * correctCell = [self.tableView cellForRowAtIndexPath:indexPath];
                        //get the correct cell (it might have changed)
                        [[correctCell imageView] setImage:thumbnail];
                        [correctCell setNeedsLayout];
                    }
                });
            }
        });
    return cell;
    }

如果您使用某种单例映像存储管理器,则希望该管理器处理缓存/数据库访问的详细信息,从而简化了此示例.

If you are using some kind of singleton image store manager, you would expect the manager to deal with the details of cache / database access, which simplifies this example.

这部分

            UIImage* thumbnail = //get thumbnail from photo id dictionary (fastest)
            if (!thumbnail) {    //if it's not in the dictionary
                thumbnail =      //get it from the cache  (slower)
                                 // update the dictionary
                if (!thumbnail) {   //if it's not in the cache
                  thumbnail =       //fetch it from the (online?) database (slowest)
                                    // update cache and dictionary
                    }
                }

将被替换为

      UIImage* thumbnail = [[ImageManager singleton] getImage];

(您不会使用补全块,因为当您返回主队列时,您可以在GCD中有效地提供补全块)

(you wouldn't use a completion block as you are effectively providing one in GCD when you return to the main queue)

这篇关于在cellForRowAtIndexPath处从CoreData加载图像会减慢滚动速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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