0

我有一个带有自定义单元格的 UITableView,其中显示了文本和图像。(右侧的图像)。起初,一切正常,但后来我注意到滚动时,整个 tableview 都滞后了。这是因为当重新使用它们时,该应用程序可能会在单元格进入屏幕时下载单元格图像。我添加了一个 NSCache 来存储下载的图像,并告诉 cellForRowAtIndexPath 加载 imageName(如果存在),否则,再次从 Internet 下载。然而,缓存是如此的短期存储,如果我用主页按钮退出我的应用程序,然后重新进入,那么只剩下一些图像,并且必须再次下载图像。

我试图找出比缓存更长期存储图像的最佳方法。我已经阅读了一些关于 NSDirectory 和存储在应用程序库中的信息,但还没有弄清楚..

我相信,最合乎逻辑的解决方案是做这样的事情:

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

     /*stuff*/

    NSString *imageName = [dictionary objectForKey:@"Image"];
    UIImage *image = [--Cache-directory-- objectForKey:imageName]; //Try to get it from cache

    if(image) //If image was received from cache:
    {
        cell.imageView.Image = image;
    }
    else //If not in cache:
    {
        image = [--local-directory-- objectForKey:imageName]; //Check some local directory

        if(image) //If image received from directory:
        {
            cell.imageView.Image = image;
            // + Also save it to the cache?
        }
        else //If image was in neither cache or local directory, get it from the website with given URL
        {
            image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];
            //Then save to cache and to file?
        }
    }


}

图像很少更改或切换,但我愿意事先在应用程序中实现它们,因此我必须在每次添加图像时发布更新。

这在我看来是合乎逻辑的。我在正确的轨道上吗?以及如何“调用”本地目录?就像,如果我将图像添加到 NSDirectory 对象或其他东西,这不是每次都会重置吗?如何访问本地文件夹?

4

4 回答 4

3

你从错误的方向攻击这个问题......
问题是 tableView 是滞后的。
原因是您在主线程中下载图像。
即使您从光盘中读取图像,您仍然无法获得最佳滚动性能。

所以不能阻塞你的主线程。为此,您可以异步下载图片,或使用 GCD 在另一个线程中下载。

像这样:

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

     /*stuff*/  

     // this will block your main thread, bad idea..
     //image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];

     // instead call it in a separate thread  
     dispatch_queue_t imgDownloaderQueue = dispatch_queue_create("imageDownloader", NULL);
         dispatch_async(imgDownloaderQueue, ^{
         // download the image in separate thread
         UIImage *image = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]] autorelease];
         dispatch_queue_t main_queue = dispatch_get_main_queue();
         dispatch_sync(main_queue, ^{                        
            // this is called in the main thread after the download has finished, here u update the cell's imageView with the new image
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            cell.imageView.image = image;
        });
    });
    dispatch_release(imgDownloaderQueue);
}
于 2012-07-17T21:33:48.860 回答
2

无需保存所有这些图像。

如果您从 url 获取图像,则只需使用AsyncImageLoader

使用该链接并获取 ASyncImageView 的 h 和 m 文件并将它们保存在您的项目中。

在您执行此操作的地方导入 h 文件

#import 'AsyncImageView.h'

然后使用下面的代码

[[AsyncImageLoader sharedLoader] cancelLoadingURL:image.imageURL];

image.imageURL=[NSURL URLWithString:@"imageURL"];
于 2012-07-17T20:47:01.377 回答
1

似乎最好的解决方案可能是使用核心数据。但与@Anachid 建议的不同,您可以像以前一样从互联网加载它们并将它们放入核心数据目录。我建议您上网而不是将它们放入您的解决方案中,因为您必须更新才能获取新图片。然后从那里您可以根据需要使用它们。

于 2012-07-17T20:35:39.583 回答
1

我最近在 UITableView 上工作,我遇到了类似的问题。我使用的一个解决方法是因为图像很小(我假设你的也是)并且具有唯一的名称,我将它们存储在应用程序的本地文档文件夹中,并使用核心数据来保存对图像位置的引用。我从那个位置加载图像。如果图像改变,我改变那些图像。不过,这可能不是最优雅的方法。只是一个建议。

至于访问本地应用程序目录,我用这个

// INSTANCE METHOD - get the path and file name for the saved plist
- (NSString *)getFileLocation:(NSString *)location {
    // Get all available file system paths for the user
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    // Get the "Documents" directory path - it's the one and only on iPhone OS
    NSString *documentsPath = [paths objectAtIndex:0];

    // Specify the file name, appending it to documentsPath above
    NSString *savedFileName = [documentsPath stringByAppendingPathComponent:location];
    NSLog(@"File Location %@", location);
    // We're done
    return savedFileName;
}
于 2012-07-17T20:31:10.213 回答