多线程:下载管理器(模拟 SDWebImage)

来源:互联网 发布:java字符串数组初始化 编辑:程序博客网 时间:2024/06/06 00:38
#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
0 0