2012-07-17 67 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); 
}