2012-07-17 40 views
0

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

我想找出最好的方式来存储图像比缓存更长期。我看过一些关于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对象或其他东西,是不是每次都会重置?我如何访问本地文件夹?

回答

2

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

如果从一个网址让你的形象就用AsyncImageLoader

使用链接及得到ASyncImageView的H和M文件并将其保存在您的项目。

导入.h文件在任何你正在做这个

#import 'AsyncImageView.h' 

然后用下面的代码

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

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

好吧,我会试试这个,但是这不会导致每次启动它时tableview都会变空,最终会自动填充?这些图像会被快速更新,而且我不希望在第一次启动应用程序时看到没有图像的单元格。 – Sti 2012-07-17 21:04:45

+0

或者至少,每次您退出该过程时,它似乎都是如此。很不错! – Sti 2012-07-17 21:15:52

+0

有没有办法在图像准备就绪时加载图像,而不是直到单元重新进入屏幕才加载图像?或者我可以在前8行的viewDidLoad中设置图像吗? – Sti 2012-07-17 21:26:14

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; 
} 
+0

只记得:当你做一个Web服务上拉,你不本地存储在某些格式(如JSON)所有的数据?如果是这样,那么图像不会以JSON值内的二进制数据的形式回来吗?如果是这样,那么我不明白为什么每次回收一个单元格时都要重新加载图像。如果你不把数据与你的网络服务一起返回,也许你可以试试看看你是否有更好的响应时间。 – Steven 2012-07-17 20:34:59

+0

我使用JSON是的,但只是为了得到图像的名称(以及其他数据(标题,说明)),如“1.png,2.png”等。然后,我用UIImage获取图像* image = [[ UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[@“www.example.com/%@”,imageName]];那么,不完全是这样,但有一些字符串解析的东西,以及..但我只是得到的名字。我应该将整个图像保存在数据库中吗?可能最多是50张图像,每张500 * 150像素。 – Sti 2012-07-17 20:55:41

1

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

+0

好的,是的,我同意。我试图阅读一些核心数据,但我发现很难快速学习..你知道任何教程,或短,但通过有关它的文章?我不知道从哪里开始,我认为我误解了Core Data的使用,以及它究竟是什么。 – Sti 2012-07-17 20:59:16

+0

基本上,您设置了数据模型,然后通过您的应用程序填充数据。这意味着你的应用程序需要在每次新启动时(从网页)获取图片,并将它们加载到核心数据中。从这一点,你可以从中获取你的数据。这里有大量的材料,只是取决于你想要的东西,我在YouTube上看到了一些很好的教程。 – 2012-07-17 21:57:20

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