写了个图片下载器,当然没法跟SDWebImageDownloader比,SDWebImageDownloader考虑到了各个方方面面,但是大致的下载器的框架时出来了,更最重要的是这种编程的思想,说到这,想起了高中化学老师的一句话:有思路就有出路,个人觉得编程也是如此,编程的思想更重要!!!
JGWebImgOperation.h
#import
#import "JGWebImgDownloader.h"
#import@interface JGWebImgOperation : NSOperation
-(id)initWithUrlStr:(NSString*)urlStr
Progress:(JGWebImgDownloaderProgress)progressBlock
Finished:(JGWebImgDownloaderFinished)finishedBlock
Cancel:(JGWebImgDownloaderCancel)cancelBlock;
@end
JGWebImgOperation.m
#import "JGWebImgOperation.h"
@interface JGWebImgOperation ()
@property(nonatomic,copy)NSString *urlStr;
@property(nonatomic,copy)JGWebImgDownloaderProgress progressBlock;
@property(nonatomic,copy)JGWebImgDownloaderFinished finishedBlock;
@property(nonatomic,copy)JGWebImgDownloaderCancel cancelBlock;
@property(nonatomic,strong)NSMutableData *imgData;
@property(nonatomic,assign)NSInteger expectSize;
@property(nonatomic,assign)NSInteger downTimeout;
@property(nonatomic,assign)BOOL isFinished;
@end
/**
初始化一个下载操作
@param urlStr 图片的路径
@param progressBlock 图片下载过程中进度回调
@param finishedBlock 图片下载完(包括下载失败)回调
@ cancelBlock 取消操作的回调
**/
-(id)initWithUrlStr:(NSString*)urlStr
Progress:(JGWebImgDownloaderProgress)progressBlock
Finished:(JGWebImgDownloaderFinished)finishedBlock
Cancel:(JGWebImgDownloaderCancel)cancelBlock
{
if (self = [super init]) {
_urlStr = urlStr;
_progressBlock = [progressBlock copy];
_finishedBlock = [finishedBlock copy];
_cancelBlock = [cancelBlock copy];
_isFinished = NO;
}
return self;
}
/**
重写NSOperation的main方法, 具体任务都封装在此方法中
**/
-(void)main
{
NSURL *url = [NSURL URLWithString:_urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:_downTimeout];
//NSURLConnection xcode7.1好几个方法都被废弃了,不过尽管废弃了,还可以用
NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connect start];
//保存图片下载完或者失败后才退出此函数
while (!_isFinished) {
[[NSRunLoop currentRunLoop] run];
}
NSLog(@"finished");
}
-(NSMutableData*)imgData
{
if (!_imgData) {
_imgData = [NSMutableData data];
}
return _imgData;
}
#pragma mark ------NSURLConnectionDataDelegate-------
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
dispatch_async(dispatch_get_main_queue(), ^{
if (_finishedBlock) {
_finishedBlock(nil,nil,nil,YES);
}
});
_isFinished = YES;
NSLog(@"failed down with error %@ ",error);
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
_expectSize = response.expectedContentLength;
NSLog(@"respoinse : %@",response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//追加数据
[self.imgData appendData:data];
if (_progressBlock) {
_progressBlock(self.imgData.length,_expectSize);
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
UIImage *image = [[UIImage alloc] initWithData:self.imgData];
//成功回调可能更新UI操作,故而使用主队列,保证UI操作在主线程中
dispatch_async(dispatch_get_main_queue(), ^{
if (_finishedBlock) {
_finishedBlock(image,self.imgData,nil,YES);
}
});
_isFinished = YES;
}
JGWebImgDownloader.h
#import<Foundation/Foundation.h>
#import<UIKit/UIKit.h>
@class JGWebImgOperation;
typedef void(^JGWebImgDownloaderProgress)(NSInteger recesiveSize,NSInteger expectSize);
typedef void(^JGWebImgDownloaderFinished)(UIImage *image,NSData *data,NSError *error,BOOL isFinish);
typedef void (^JGWebImgDownloaderCancel)();
@interface JGWebImgDownloader : NSObject
/**
获取下载器全局单列
**/
+(id)shareJGWebIMgDownLoader;
/**
下载图片
@param urlStr 图片路径
@param progressBlock 进度回调
@param finishedBlock 下载图片后回调
**/
-(JGWebImgOperation*)downImgWithUrlStr:(NSString*)urlStr
Progree: (JGWebImgDownloaderProgress)progressBlock
Finished:(JGWebImgDownloaderFinished)finishedBlock;
@end
JGWebImgDownloader.m
#define finishedCallbackKey @"finishedCallbackKey"
#define progressCallbackKey @"progressCallbackKey"
#import "JGWebImgDownloader.h"
#import "JGWebImgOperation.h"
@interface JGWebImgDownloader()
@property(nonatomic,strong)NSMutableArray *operationArr;
@property(nonatomic,strong)NSMutableDictionary *callbackDict;
//下载队列了
@property(nonatomic,strong)NSOperationQueue *downOperationQueue;
@property(nonatomic,strong)dispatch_queue_t barrierQueue;
@end
static JGWebImgDownloader *shareDownloader = nil;
/**
单列
**/
+(id)shareJGWebIMgDownLoader
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shareDownloader = [[JGWebImgDownloader alloc] init];
});
return shareDownloader;
}
/**
简单的初始化
**/
-(id)init
{
if (self = [super init])
{
[self createDownLoadQueue];
_barrierQueue = dispatch_queue_create("com.text.jg", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
-(void)dealloc
{
[self.downOperationQueue cancelAllOperations];
}
-(void)createDownLoadQueue
{
_downOperationQueue = [[NSOperationQueue alloc]init];
_downOperationQueue.maxConcurrentOperationCount = 3;
}
/**
下载图片
@param urlStr 图片路径
@param progressBlock 进度回调
@param finishedBlock 下载图片后回调
**/
-(JGWebImgOperation*)downImgWithUrlStr:(NSString*)urlStr
Progree:(JGWebImgDownloaderProgress)progressBlock
Finished:(JGWebImgDownloaderFinished)finishedBlock
{
__block JGWebImgOperation *operation = nil;
__weak typeof(self) sf = self;
[self addCallbackFinished:finishedBlock
Progress:progressBlock
ForurlStr:urlStr
CreateOperation:^{
operation = [[JGWebImgOperation alloc] initWithUrlStr:urlStr Progress:^(NSInteger recesiveSize, NSInteger expectSize) {
__block NSArray *array = nil;
dispatch_barrier_sync(_barrierQueue, ^{
array = self.callbackDict[urlStr];
});
for (NSDictionary *dict in array) {
JGWebImgDownloaderProgress progress = dict[progressCallbackKey];
if (progress) {
progress(recesiveSize,expectSize);
}
}
} Finished:^(UIImage *image, NSData *data, NSError *error, BOOL isFinish) {
__block NSArray *array = nil;
dispatch_barrier_sync(_barrierQueue, ^{
array = self.callbackDict[urlStr];
if (isFinish) {
[self.callbackDict removeObjectForKey:urlStr];
}
});
for (NSDictionary *dict in array) {
JGWebImgDownloaderFinished finished = dict[finishedCallbackKey];
if (finished) {
finished(image,data,error,isFinish);
}
}
} Cancel:^{
dispatch_barrier_async(_barrierQueue, ^{
[self.callbackDict removeObjectForKey:urlStr];
});
}];
[sf.downOperationQueue addOperation:operation];
}];
return operation;
}
/**
保存回调block,并判断是非在下载,如果没有下载,创建下载任务
**/
-(void)addCallbackFinished:(JGWebImgDownloaderFinished)finishedBlock
Progress:(JGWebImgDownloaderProgress)progressBlock
ForurlStr:(NSString*)urlStr
CreateOperation:(void (^)()) createOperaion
{
if (!urlStr || [urlStr isEqualToString:@""]) {
if (finishedBlock) {
finishedBlock(nil,nil,nil,NO);
return;
}
}
//需要判断是否在下载中
dispatch_barrier_sync(self.barrierQueue, ^{
BOOL isFirst = NO;
NSArray *callbacks = self.callbackDict[urlStr];
if (!callbacks) {
self.callbackDict[urlStr] = [NSMutableArray array];
isFirst = YES;
}
if (isFirst) {
//self.callbackDict为临界资源,避免多个线程同时操作,故而使用了 dispatch_barrier_async
NSMutableArray *array = self.callbackDict[urlStr];
NSMutableDictionary *callbackDt = [NSMutableDictionary dictionary];
if (finishedBlock) {
callbackDt[finishedCallbackKey] = [finishedBlock copy];
}
if (progressBlock) {
callbackDt[progressCallbackKey] = [progressBlock copy];
}
[array addObject:callbackDt];
if (createOperaion)
{
createOperaion();
}
}
});
}
-(NSMutableArray*)operationArr
{
if (!_operationArr) {
_operationArr = [NSMutableArray array];
}
return _operationArr;
}
-(NSMutableDictionary*)callbackDict
{
if (!_callbackDict) {
_callbackDict = [NSMutableDictionary dictionary];
}
return _callbackDict;
}
使用
JGWebImgDownloader *imageDownloader = [JGWebImgDownloader shareJGWebIMgDownLoader];
[imageDownloader downImgWithUrlStr:@"http://www.blisscake.cn/Upload/Product/Show/Source/ps_1507201119031647109.jpg" Progree:^(NSInteger recesiveSize, NSInteger expectSize) {
NSLog(@"download rate : %.5f", recesiveSize/(double)expectSize);
} Finished:^(UIImage *image, NSData *data, NSError *error, BOOL isFinish) {
_imgView.image = image;
}];
代码有点乱啊 ,有个makedown的编辑器可以编辑代码,不会这么乱,不会用,下次学学。