存储来自Web的UITableView图像

时间:2012-07-17 20:21:08

标签: iphone ios image uitableview web

我有一个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 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分:2)

Theres无需保存所有这些图像。

如果您从网址获取图片,请使用AsyncImageLoader

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

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

#import 'AsyncImageView.h'

然后使用以下代码

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

image.imageURL=[NSURL URLWithString:@"imageURL"];

答案 2 :(得分:1)

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

至于访问本地app目录,我使用这个

// 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;
}

答案 3 :(得分:1)

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