圖片下載器


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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容