ios--多圖下載,優化cell
阿新 • • 發佈:2018-12-11
1.需求:在tableview的每一個cell裡顯示從網路下載的圖片
2.demo:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *ID = @"app"; //1.建立cell UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; //2.設定cell資料//2.1拿到該行cell對應的資料 JKYApp *appM = self.apps[indexPath.row]; cell.textLabel.text = appM.name; cell.detailTextLabel.text = appM.download; //設定圖示 UIImage *image = [self.imageDic objectForKey:appM.icon]; if (image) { cell.imageView.image = image; }else{ NSURL *url = [NSURL URLWithString:appM.icon]; NSData*imageData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imageData]; cell.imageView.image = image; //將圖片儲存到記憶體快取 [self.imageDic setObject:image forKey:appM.icon]; } //3.返回cell return cell; }
3.問題:
-
UI不流暢
dataWithContentsOfURL:是耗時操作,將其放在主執行緒會造成卡頓。如果圖片很多,圖片很大,而且網路情況不好的話會造成使用者體驗極差。
-
圖片重複下載
由於沒有快取機制,即使下載完成並顯示了當前cell的圖片,但是當該cell再一次滾動,顯示的時候還是會下載它所對應的圖片,耗費了下載流量,而且還導致重複操作。
4.解決方案
1、圖片的URL:因為每張圖片對應的URL都是唯一的,所以我們可以通過它來建立圖片快取和下載操作的快取的鍵,以及拼接沙盒快取的路徑字串。
2、圖片快取(字典):存放於記憶體中;鍵為圖片的URL,值為UIImage物件。作用:讀取速度快,直接使用UIImage物件。
3、下載操作快取(字典):存放與記憶體中,鍵為圖片的URL,值為NSBlockOperation物件。作用:用來避免對於同一張圖片還要開啟多個下載執行緒。
4、沙盒快取(檔案路徑對應NSData):存放於磁碟中,位於Cache資料夾內,路徑為“Cache/圖片URL的最後的部分”,值為NSData物件(將UIImage轉化為NSData才能寫入磁盤裡)。作用:程式斷網,再次啟動也可以直接在磁碟中拿到圖片。
程式碼:
/先去檢視記憶體快取中該圖片時候已經存在,如果存在那麼久直接拿來用,否則去檢查磁碟快取 //如果有磁碟快取,那麼儲存一份到記憶體,設定圖片,否則就直接下載 //1)沒有下載過 //2)重新開啟程式 UIImage *image = [self.images objectForKey:appM.icon]; if (image) { cell.imageView.image = image; NSLog(@"%zd處的圖片使用了記憶體快取中的圖片",indexPath.row) ; }else { //儲存圖片到沙盒快取 NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; //獲得圖片的名稱,不能包含/ NSString *fileName = [appM.icon lastPathComponent]; //拼接圖片的全路徑 NSString *fullPath = [caches stringByAppendingPathComponent:fileName]; //檢查磁碟快取 NSData *imageData = [NSData dataWithContentsOfFile:fullPath]; //廢除 imageData = nil; if (imageData) { UIImage *image = [UIImage imageWithData:imageData]; cell.imageView.image = image; NSLog(@"%zd處的圖片使用了磁碟快取中的圖片",indexPath.row) ; //把圖片儲存到記憶體快取 [self.images setObject:image forKey:appM.icon]; // NSLog(@"%@",fullPath); }else { //檢查該圖片時候正在下載,如果是那麼久什麼都捕捉,否則再新增下載任務 NSBlockOperation *download = [self.operations objectForKey:appM.icon]; if (download) { }else { //先清空cell原來的圖片 cell.imageView.image = [UIImage imageNamed:@"Snip20160221_306"]; download = [NSBlockOperation blockOperationWithBlock:^{ NSURL *url = [NSURL URLWithString:appM.icon]; NSData *imageData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imageData]; NSLog(@"%zd--下載---",indexPath.row); //容錯處理 if (image == nil) { [self.operations removeObjectForKey:appM.icon]; return ; } //演示網速慢的情況 //[NSThread sleepForTimeInterval:3.0]; //把圖片儲存到記憶體快取 [self.images setObject:image forKey:appM.icon]; //NSLog(@"Download---%@",[NSThread currentThread]); //執行緒間通訊 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ //cell.imageView.image = image; //重新整理一行 [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft]; //NSLog(@"UI---%@",[NSThread currentThread]); }]; //寫資料到沙盒 [imageData writeToFile:fullPath atomically:YES]; //移除圖片的下載操作 [self.operations removeObjectForKey:appM.icon]; }]; //新增操作到操作快取中 [self.operations setObject:download forKey:appM.icon]; //新增操作到佇列中 [self.queue addOperation:download]; } } } //3.返回cell return cell;
5.記憶體警告處理
-(void)didReceiveMemoryWarning { [self.images removeAllObjects]; //取消佇列中所有的操作 [self.queue cancelAllOperations]; }
原文連結:https://www.jianshu.com/p/612d5fdccb7f