多线程:下载管理器(模拟 SDWebImage)
2016-03-31 15:50
288 查看
#import "ViewController.h" #import "DownLoadImageManager.h" #import "AppInfo.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @property (nonatomic, copy) NSString *currentURL; // 记录当前下载的URL @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. NSLog(@"%@",NSHomeDirectory()); } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { NSArray *data = [AppInfo appInfoList]; // 连续点击的时候,只显示最后一张 AppInfo *app = data[arc4random_uniform(data.count)]; // 判断要下载的URL跟上一个下载的URL的关系 if (![app.icon isEqualToString:self.currentURL] && self.currentURL) { // 取消上一个下载操作 [[DownLoadImageManager shareManager]cancelDownload:self.currentURL]; } self.currentURL = app.icon; [[DownLoadImageManager shareManager]downloadOperationWithURLString:app.icon finish:^(UIImage *image) { self.imageView.image = image; }]; } - (IBAction)cancel:(id)sender { } @end
#import <UIKit/UIKit.h> @interface DownLoadOperation : NSOperation // 创建一个下载操作 + (instancetype)downloadOperationWithURLString:(NSString *)URLString finish:(void(^)(UIImage *image))finish; @end #import "DownLoadOperation.h" #import "NSString+Path.h" @interface DownLoadOperation () // 图片下载的URLString @property (nonatomic, copy) NSString *URLString; // 下载完成之后的回调 @property (nonatomic, copy) void(^finish)(UIImage *image); @end @implementation DownLoadOperation // 线程入口 - (void)main { // 需要添加自动释放池 @autoreleasepool { // 断言 (只在debug模式下有作用)在上架之后不起作用 NSAssert(self.finish != nil, @"完成回调不能为空"); // 下载操作 // 首先要有网址 NSURL *url = [NSURL URLWithString:self.URLString]; // 接收二进制数据 NSData *data = [NSData dataWithContentsOfURL:url]; // 如果有数据就保存图片 if (data) { NSLog(@"%@",NSHomeDirectory()); // 2. 沙盒缓存 [data writeToFile:[self.URLString appendCache] atomically:YES]; } // 关键节点判断 (耗时操作) if (self.isCancelled) { NSLog(@"操作已经被取消"); // 操作已经被取消 return; } UIImage *image = [UIImage imageWithData:data]; // 完成之后的回调 // 下载完成之后,回到主线程调用 [[NSOperationQueue mainQueue]addOperationWithBlock:^{ self.finish(image); }]; } } + (instancetype)downloadOperationWithURLString:(NSString *)URLString finish:(void (^)(UIImage *))finish { DownLoadOperation *op = [[self alloc]init]; op.URLString = URLString; op.finish = finish; return op; } // SDWebImage 在start 方法中取消正在执行的操作 (已经提交了几千份代码) // 不管操作是否已经被取消,都会调用 start 方法 // 如果重写start 方法来取消操作,很非常麻烦 // 有兴趣可以去看SDWebImage 的 start 方法 //- (void)start { // NSLog(@"cancel = %d",self.isCancelled); // if (self.isCancelled)return; // //// NSLog(@"%s",__FUNCTION__); // [super start]; // //} @end
#import <UIKit/UIKit.h> @interface DownLoadImageManager : NSObject + (instancetype)shareManager; - (void)downloadOperationWithURLString:(NSString *)URLString finish:(void(^)(UIImage *image))finish; - (void)cancelDownload:(NSString *)URLString; @end #import "DownLoadImageManager.h" #import "DownLoadOperation.h" #import "NSString+Path.h" @interface DownLoadImageManager () @property (nonatomic, strong) NSOperationQueue *queue; // 队列 @property (nonatomic, strong) NSMutableDictionary *operationCache; // 操作缓存池 @property (nonatomic, strong) NSMutableDictionary *imageCache; // 图片缓存池 @end @implementation DownLoadImageManager + (instancetype)shareManager { static dispatch_once_t onceToken; static id instance; dispatch_once(&onceToken, ^{ instance = [[self alloc]init]; }); return instance; } - (void)downloadOperationWithURLString:(NSString *)URLString finish:(void (^)(UIImage *))finish { NSAssert(finish != nil, @"完成回调不能为空"); // 判断有没有缓存 if ([self checkCache:URLString]) { // 有缓存 // 不需要管缓存是以什么形式过来的,只需要从内存中读取图片就可以 UIImage *image = [self.imageCache objectForKey:URLString]; finish(image); return; } // 创建操作 DownLoadOperation * op = [DownLoadOperation downloadOperationWithURLString:URLString finish:^(UIImage *image) { // 移除操作 [self.operationCache removeObjectForKey:URLString]; // 把图片缓存起来 if (image) { [self.imageCache setObject:image forKey:URLString]; } finish(image); }]; // 添加到队列 [self.queue addOperation:op]; // 把操作缓存起来 [self.operationCache setObject:op forKey:URLString]; } - (BOOL)checkCache:(NSString *)URLString { // 判断是否有缓存 // 先判断内存缓存,再判断沙盒缓存 if ([self.imageCache objectForKey:URLString]) { NSLog(@"内存缓存"); // 有缓存 return YES; } // 判断沙盒 // 取出沙盒缓存 NSString *path = [URLString appendCache]; NSData *data = [NSData dataWithContentsOfFile:path]; UIImage *image = [UIImage imageWithData:data]; if (image) { NSLog(@"沙盒缓存"); // 缓存到内存 [self.imageCache setObject:image forKey:URLString]; return YES; } return NO; } // 取消操作 - (void)cancelDownload:(NSString *)URLString { // 取出对应的操作 DownLoadOperation *op = [self.operationCache objectForKey:URLString]; [op cancel]; } - (NSMutableDictionary *)operationCache { if (_operationCache == nil) { _operationCache = [NSMutableDictionary dictionary]; } return _operationCache; } - (NSMutableDictionary *)imageCache { if (_imageCache == nil) { _imageCache = [NSMutableDictionary dictionary]; } return _imageCache; } - (NSOperationQueue *)queue { if (_queue == nil) { _queue = [[NSOperationQueue alloc]init]; // SDWebImage 也是 6 _queue.maxConcurrentOperationCount = 6; } return _queue; } @end
相关文章推荐
- APP Run In Background(App 的后台运行)
- Eclipse常用设置
- 笔记 AsyncTask运行原理
- xcode7.2如何真机测试iOS9.3系统
- 使用git pull文件时和本地文件冲突怎么办?
- 通过url地址获取数据后将数据利用SpringMVC的@ResponseBody返回中文可能出现乱码地方
- iOS之隐藏/显示tabbar
- 归并排序的使用
- IOS折线统计图
- 李彦宏:数据技术共享与“圈子联合文化”
- ExecutorService的几种关闭线程池方法
- ssh 无密码登陆
- SecurCRT命令回显设置
- 详解JavaScript表单验证(E-mail 验证)
- linux 安装svn服务端
- Linux修改内核使得普通用户可以打印kmsg内容
- 花指令
- springMVC 上传文件
- 火狐浏览器sqlite插件
- 压缩包里面excel 导出 (跨行跨列)