多圖下載代碼

  • LZAppItem模型類
// LZAppItem.h
#import <Foundation/Foundation.h>

@interface LZAppItem : NSObject

/** 名稱*/
@property (nonatomic ,strong) NSString *name;
/** 圖標(biāo)的地址*/
@property (nonatomic ,strong) NSString *icon;
/** 下載量*/
@property (nonatomic ,strong) NSString *download;

+(instancetype)appItemWithDict:(NSDictionary *)dict;

@end

// LZAppItem.m
#import "LZAppItem.h"

@implementation LZAppItem

+ (instancetype)appItemWithDict:(NSDictionary *)dict
{
    // 創(chuàng)建對象
    LZAppItem *appItem = [[LZAppItem alloc] init];
    // KVC
    [appItem setValuesForKeysWithDictionary:dict];
    // 返回對象
    return appItem;
}

@end
  • ViewController
// ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UITableViewController


@end

// ViewController.m
#import "ViewController.h"
#import "LZAppItem.h"

@interface ViewController ()
/** 隊列*/
@property (nonatomic ,strong) NSOperationQueue *queue;
/** 模型數(shù)組*/
@property (nonatomic, strong) NSArray *apps;
/** 圖片緩存*/
@property (nonatomic ,strong) NSMutableDictionary *images;
/** 操作*/
@property (nonatomic ,strong) NSMutableDictionary *operations;
@end

@implementation ViewController

#pragma mark - 懶加載數(shù)據(jù)
- (NSArray *)apps
{
    if (_apps == nil) {
        // 1獲取字典數(shù)組
        // 1.1獲取路徑
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil];
        // 1.2獲取到字典數(shù)組
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:filePath];
        // 2.拿到模型數(shù)組
        // 2.1創(chuàng)建一個可變數(shù)組
        NSMutableArray *temp = [NSMutableArray array];
        // 2.2創(chuàng)建for循環(huán)
        for (NSDictionary *dict in dictArray) {
            LZAppItem *item = [LZAppItem appItemWithDict:dict];
            [temp addObject:item];
        }
        _apps = temp;
    }
    return _apps;
}

#pragma mark - 圖片緩存
- (NSMutableDictionary *)images
{
    if (_images == nil) {
        _images = [NSMutableDictionary dictionary];
    }
    return _images;
}

#pragma mark - 隊列
- (NSOperationQueue *)queue
{
    if (_queue == nil) {
        _queue = [[NSOperationQueue alloc] init];
        _queue.maxConcurrentOperationCount = 3;
    }
    return _queue;
}

#pragma mark - UITableViewDataSource方法
// 返回多少組
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

// 每組返回多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return self.apps.count;
}

// 每行顯示什么內(nèi)容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"app";
    // 去緩存池里面找
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
    }

    // 拿到模型數(shù)據(jù)
    LZAppItem *item = self.apps[indexPath.row];
    // 賦值
    cell.textLabel.text = item.name;
    cell.detailTextLabel.text = item.download;

    // 賦值圖片握侧,重點(diǎn)

    // 檢查緩存,用圖片的地址做鍵
    UIImage *image = [self.images objectForKey:item.icon];
    if (image) { // 有內(nèi)存緩存打却,即身上有錢
        // 直接賦值
        cell.imageView.image = image;
//        NSLog(@"%zd使用了內(nèi)存緩存",indexPath.row);
    }else { // 沒有內(nèi)存緩存熊楼,即身上沒有錢

        // 獲取磁盤緩存路徑
        // 0.0獲取路徑
        NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        // 0.1得到圖片的名稱
        NSString *fileName = [item.icon lastPathComponent];
        // 0.2拼接文件的路徑
        NSString *fullPath = [cachePath stringByAppendingPathComponent:fileName];

        // 去檢查磁盤緩存,這里找到的是保存在cache里面的NSData數(shù)據(jù)
        NSData *imgData = [NSData dataWithContentsOfFile:fullPath];

        if (imgData) { // 如果磁盤緩存里面有該圖片辫狼,磁盤緩存即是卡里面有錢
            // 拿到Image
            UIImage *image = [UIImage imageWithData:imgData];
            cell.imageView.image = image;

            // 把圖片保存到身上厘熟,內(nèi)存緩存
            [self.images setObject:image forKey:item.icon];

//            NSLog(@"%zd使用了磁盤緩存",indexPath.row);

        } else { // 如果磁盤緩存里面沒有該圖片,磁盤緩存即是卡里面沒有錢
            // 來到這里蘸吓,說明又沒有內(nèi)存緩存车海,又沒有磁盤緩存
            // 清空圖片或者是設(shè)置占位圖片枢舶,目的是什么赶么,因為cell是重復(fù)利用的肩豁,假設(shè)當(dāng)你第一張圖片顯示完畢的時候,用戶繼續(xù)往下拖拽辫呻,下面的cell是由上面消失的cell重復(fù)利用過來的清钥,而下面的cell去下載圖片的時間可能比較長,所以顯示的效果是上一張殘留下來的圖片放闺,之后再把從網(wǎng)絡(luò)下載的圖片進(jìn)行覆蓋祟昭,也就是圖片錯亂了,所以怖侦,為了防止這個問題篡悟,用一張占位圖片解決
            cell.imageView.image = [UIImage imageNamed:@"Snip20200808_172"];

            /*避免重復(fù)操作,當(dāng)程序第一次運(yùn)行起來的時候匾寝,顯示第一個cell的時候搬葬,創(chuàng)建一個操作去服務(wù)器端獲取數(shù)據(jù),然后用戶又隨便往下拖拽艳悔,那么第一個cell就不再顯示了急凰,此時那個獲取數(shù)據(jù)的操作還在執(zhí)行,假設(shè)需要10秒猜年,然后用戶又隨便拖拽抡锈,滾到了第一個cell,第一個cell又重新顯示出來了码倦,那么它還會繼續(xù)創(chuàng)建一個操作去服務(wù)器端獲取數(shù)據(jù)企孩,那么可能就有好幾個操作發(fā)送到服務(wù)器端去獲取同一個數(shù)據(jù)了,沒有必要袁稽,所以勿璃,這里采用了一個可變字典,用來判斷,好辦法补疑,誰想出來的歧沪,牛逼*/
            // 檢查操作緩存
            NSBlockOperation *dowbloadOperation = [self.operations objectForKey:item.icon];
            if (dowbloadOperation) { // 如果有操作,說明之前已經(jīng)發(fā)了一次操作過去了莲组,那么再次來到這的時候诊胞,就不能再發(fā)請求了,所以什么也不能做

            } else { // 如果沒有操作锹杈,說明之前沒有發(fā)過操作過去撵孤,要添加操作
                    dowbloadOperation = [NSBlockOperation blockOperationWithBlock:^{


                    // 1.創(chuàng)建url
                    NSURL *url = [NSURL URLWithString:item.icon];
                    // 2.拿到二進(jìn)制數(shù)據(jù)
                    // 該方法通過url獲取數(shù)據(jù)是有時間限制的,30秒,如果失敗竭望,返回nil
                    NSData *data = [NSData dataWithContentsOfURL:url];
                    // 3.轉(zhuǎn)化為UIImage對象
                    UIImage *image = [UIImage imageWithData:data];
                    // 4.判斷
                    if (image == nil) {
                        // 把這次操作刪除掉
                        [self.operations removeObjectForKey:item.icon];
                        return ;
                    }
                    // 5.保存到內(nèi)存緩存
                    [self.images setValue:image forKey:item.icon];
                    // 6.保存到磁盤緩存
                    [data writeToFile:fullPath atomically:YES];

                    NSLog(@"%zd直接下載",indexPath.row);

                    // 設(shè)置圖片
                   // 下面這行代碼應(yīng)該放在主線程,那么應(yīng)該回到主線程
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        // 下面這個block塊里面的代碼是在主線程執(zhí)行的
                        // 如果沒有刷新操作邪码,那么不會顯示圖片,為什么咬清,因為你雖然賦值了闭专,但是沒有
                        // 調(diào)用它的layoutsubviews創(chuàng)建尺寸,只有調(diào)用layoutsubviews才會顯示出圖片
                        // 也就是刷新,或者點(diǎn)擊某一行的時候旧烧,它會觸發(fā)layoutsubviews方法影钉,那么才會
                        // 顯示出圖片了,但是掘剪,你用reloadData又沒有必要平委,只需要設(shè)置某一張圖片,你刷新
                        // 整個可視區(qū)域杖小,那就傻逼了肆汹,所以愚墓,這里面最好的方式是予权,刷新特定的行數(shù)
//                        cell.imageView.image = image;
//                        [tableView reloadData];
                        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
                    }];

                }];

                // 添加操作到內(nèi)存緩存中
                [self.operations setObject:dowbloadOperation forKey:item.icon];

                // 添加到隊列
                [self.queue addOperation:dowbloadOperation];
            }

        }
    }

    // 返回cell
    return cell;
}

- (void)didReceiveMemoryWarning
{
    // 移除內(nèi)存緩存
    [self.images removeAllObjects];
    // 取消隊列中的操作
    [self.queue cancelAllOperations];
}
@end

  • 效果圖片:
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浪册,隨后出現(xiàn)的幾起案子扫腺,更是在濱河造成了極大的恐慌,老刑警劉巖村象,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件笆环,死亡現(xiàn)場離奇詭異,居然都是意外死亡厚者,警方通過查閱死者的電腦和手機(jī)躁劣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來库菲,“玉大人账忘,你說我怎么就攤上這事。” “怎么了鳖擒?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵溉浙,是天一觀的道長。 經(jīng)常有香客問我蒋荚,道長戳稽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任期升,我火速辦了婚禮惊奇,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘播赁。我一直安慰自己赊时,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布行拢。 她就那樣靜靜地躺著祖秒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舟奠。 梳的紋絲不亂的頭發(fā)上竭缝,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機(jī)與錄音沼瘫,去河邊找鬼抬纸。 笑死,一個胖子當(dāng)著我的面吹牛耿戚,可吹牛的內(nèi)容都是我干的湿故。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼膜蛔,長吁一口氣:“原來是場噩夢啊……” “哼坛猪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起皂股,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤墅茉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后呜呐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體就斤,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年蘑辑,在試婚紗的時候發(fā)現(xiàn)自己被綠了洋机。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡洋魂,死狀恐怖绷旗,靈堂內(nèi)的尸體忽然破棺而出啄踊,到底是詐尸還是另有隱情,我是刑警寧澤刁标,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布颠通,位于F島的核電站,受9級特大地震影響膀懈,放射性物質(zhì)發(fā)生泄漏顿锰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一启搂、第九天 我趴在偏房一處隱蔽的房頂上張望硼控。 院中可真熱鬧,春花似錦胳赌、人聲如沸牢撼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽熏版。三九已至,卻和暖如春捍掺,著一層夾襖步出監(jiān)牢的瞬間撼短,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工挺勿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留曲横,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓不瓶,卻偏偏與公主長得像禾嫉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蚊丐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容