1. 程式人生 > >ios--多圖下載,優化cell

ios--多圖下載,優化cell

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