? ? 寫了個圖片下載器,當然沒法跟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的編輯器可以編輯代碼,不會這么亂,不會用,下次學學。