NSOperation(Queue) 多圖片下載

NSOperation NSOperationQueue 的使用
apps.plist

1-apps.plist.png

ZYXApp.h

#import <Foundation/Foundation.h>

@interface ZYXApp : NSObject
/** 圖標 */
@property (nonatomic, strong) NSString *icon;
/** 下載量 */
@property (nonatomic, strong) NSString *download;
/** 名字 */
@property (nonatomic, strong) NSString *name;

+ (instancetype)appWithDict:(NSDictionary *)dict;
@end

ZYXApp.m

#import "ZYXApp.h"

@implementation ZYXApp
+ (instancetype)appWithDict:(NSDictionary *)dict
{
    ZYXApp *app = [[self alloc] init];
    [app setValuesForKeysWithDictionary:dict];
    return app;
}
@end

ViewController.m

#import "ViewController.h"

#import "ZYXApp.h"

@interface ViewController ()
/** 所有數據 */
@property (nonatomic, strong) NSArray *apps;
/** 內存緩存的圖片 url-image對象 */
@property (nonatomic, strong) NSMutableDictionary *images;
/** 所有的操作對象 url-NSOperation對象 */
@property (nonatomic, strong) NSMutableDictionary *operations;
/** 隊列對象 */
@property (nonatomic, strong) NSOperationQueue *queue;
@end



@implementation ViewController

- (NSOperationQueue *)queue
{
    if (!_queue) {
        _queue = [[NSOperationQueue alloc] init];
        _queue.maxConcurrentOperationCount = 3;
    }
    return _queue;
}

- (NSMutableDictionary *)operations
{
    if (!_operations) {
        _operations = [NSMutableDictionary dictionary];
    }
    return _operations;
}

- (NSMutableDictionary *)images
{
    if (!_images) {
        _images = [NSMutableDictionary dictionary];
    }
    return _images;
}

- (NSArray *)apps
{
    if (!_apps) {
        NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
        
        NSMutableArray *appArray = [NSMutableArray array];
        for (NSDictionary *dict in dictArray) {
            [appArray addObject:[ZYXApp appWithDict:dict]];
        }
        _apps = appArray;
    }
    return _apps;
}



- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    
    self.images = nil;
    self.operations = nil;
    [self.queue cancelAllOperations];
}

#pragma mark - 數據源方法
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.apps.count;
}

核心方法:

/**
 * 核心方法
 */
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString *ID = @"app";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    
    ZYXApp *app = self.apps[indexPath.row];
    cell.textLabel.text = app.name;
    cell.detailTextLabel.text = app.download;
    
    // 先從內存緩存中取出圖片
    UIImage *image = self.images[app.icon];
    if (image) { // 內存中有圖片
        cell.imageView.image = image;
    } else {  // 內存中沒有圖片
        // 獲得Library/Caches文件夾
        NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
        // 獲得文件名
        NSString *filename = [app.icon lastPathComponent];
        // 計算出文件的全路徑
        NSString *file = [cachesPath stringByAppendingPathComponent:filename];
        // 加載沙盒的文件數據
        NSData *data = [NSData dataWithContentsOfFile:file];
        
        if (data) { // 直接利用沙盒中圖片
            UIImage *image = [UIImage imageWithData:data];
            cell.imageView.image = image;
            // 存到字典中
            self.images[app.icon] = image;
        } else { // 下載圖片
            cell.imageView.image = [UIImage imageNamed:@"placeholder"];
            
            NSOperation *operation = self.operations[app.icon];
            if (operation == nil) { // 這張圖片暫時沒有下載任務
                operation = [NSBlockOperation blockOperationWithBlock:^{
                    // 下載圖片
                    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]];
                    // 數據加載失敗
                    if (data == nil) {
                        // 移除操作
                        [self.operations removeObjectForKey:app.icon];
                        return;
                    }
                    
                    UIImage *image = [UIImage imageWithData:data];
                    
                    // 存到字典中
                    self.images[app.icon] = image;
                    
                    // 回到主線程顯示圖片
                    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
                    }];
                    
                    // 將圖片文件數據寫入沙盒中
                    [data writeToFile:file atomically:YES];
                    // 移除操作
                    [self.operations removeObjectForKey:app.icon];
                }];
                
                // 添加到隊列中
                [self.queue addOperation:operation];
                
                // 存放到字典中
                self.operations[app.icon] = operation;
            }
        }
    }
    
    return cell;
}

@end

下載的圖片在沙盒的保存地址:

/Users/admin/Library/Developer/CoreSimulator/Devices/95A0E48B-2AF9-45A0-83AE-6C065C293B5E/data/Containers/Data/Application/8279B407-F09D-4FD8-99F1-7695B1F9FDC1/Library/Caches
2-沙盒中緩存的16張圖片.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,211評論 30 472
  • 父類實現深拷貝時,子類如何實現深度拷貝。父類沒有實現深拷貝時,子類如何實現深度拷貝。? 深拷貝同淺拷貝的區別:淺拷...
    JonesCxy閱讀 1,052評論 1 7
  • ? 深拷貝同淺拷貝的區別:淺拷貝是指針拷貝,對一個對象進行淺拷貝,相當于對指向對象的指針進行復制,產生一個新的指向...
    WSGNSLog閱讀 1,285評論 0 1
  • 27、ViewController的didReceiveMemoryWarning是在什么時候調用的?默認的操作是...
    煙雨平生花飛舞閱讀 617評論 0 1
  • 自由是一枚紅果 在四季風中高懸枝頭 一抹緋紅在藍天中輕舞 驚艷了輕盈掠過的白鷺 自由是一枚紅果 圓潤清甜,鮮美多汁...
    瑞意雋永閱讀 146評論 2 6