第三篇、简单的图片下载器

第一种:

  这是我自己封装的一个异步下载图片的下载器。

实现原理:

  1.请求服务器数据,加载本地的占位图片

  2.根据链接查找本地是否已经有缓存,有就直接加载

  3.本地没有缓存,就去下载

待完善:

  1.今后将代理改为Block来 实现,代码的易读性更强

 

使用:

        // 下载图片
        Download *ADownload = [[Download alloc]init];
        ADownload.delegate = self;
        [ADownload DownloadURL:tempString1 ImageID:

 

.h

#import <Foundation/Foundation.h>
// 不建议这样缓存文件目录
#define kDiskCachePath [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/imageCache"] @protocol DownloadDelete; //下载文件到本地 @interface Download : NSObject @property (nonatomic, weak) id <DownloadDelete> delegate; //下载文件到本地 -(void)DownloadURL:(NSString *)ADownloadURL ImageID:(NSInteger)AImageID; @end @protocol DownloadDelete <NSObject> @required //下载成功 -(void)DownloadIsSuccess:(NSData *)AImageData ImageID:(NSInteger)AImageID; //下载失败 -(void)DownloadIsFail:(NSString *)AFailMsgString ImageID:(NSInteger)AImageID; @end

 

#import "Download.h"

@interface Download ()
{

}
@property (nonatomic, retain) NSData *FImageData;
@end

@implementation Download
@synthesize delegate;
@synthesize FImageData;

//下载文件到本地
-(void)DownloadURL:(NSString *)ADownloadURL ImageID:(NSInteger)AImageID
{

    if (![[NSFileManager defaultManager] fileExistsAtPath:kDiskCachePath])
    {//如果目录imageCache不存在,创建目录
        NSError *error=nil;
        [[NSFileManager defaultManager] createDirectoryAtPath:kDiskCachePath withIntermediateDirectories:YES attributes:nil error:&error];
    }
    
    
  // 当图片的url为nil,会崩溃,需要处理一下
NSString
*AImageNameString = [ADownloadURL lastPathComponent]; //临时修改 添加 NSString *AImagePath = [kDiskCachePath stringByAppendingFormat:@"/%@",AImageNameString]; // [AImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:@"img%ld",APositionID + 1]]]; //如果有缓存图片,直接读取cache内的缓存图片 if ([[NSFileManager defaultManager] fileExistsAtPath:AImagePath]) { NSData *data = [NSData dataWithContentsOfFile:AImagePath]; [delegate DownloadIsSuccess:data ImageID:AImageID]; } else {//如果没有缓存图片,异步加载网络图片 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, ^{ NSString *AEncodingDownloadURL = [ADownloadURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL *AImagePathURL = [[NSURL alloc] initWithString:AEncodingDownloadURL]; NSData *AImageData = [[NSData alloc] initWithContentsOfURL:AImagePathURL]; if(AImageData) { FImageData = AImageData; [[NSFileManager defaultManager] createFileAtPath:AImagePath contents:AImageData attributes:nil]; } else { } }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ if (FImageData.length == 0) { //下载失败 [delegate DownloadIsFail:@"图片下载失败" ImageID:AImageID]; } else { [delegate DownloadIsSuccess:FImageData ImageID:AImageID]; } }); } }

 

第二种:

思路:

1.先设置图片的URL,并设置站位图片

2.重复下载,移除当前的操作

3.启动下载器去下载图片

4.判断内存中是否存在缓存,再判断沙盒中是否没有缓存,有直接返回,结束当前的操作,否则执行下载

5.下载完成移除相关的操作,并将图片缓存到内容中

 

// 图片的分类文件
#define JQCurrentURLString @"currentURLStirng"

@interface UIImageView ()
/**
 *  记录当前正在下载的URL
 */
@property (nonatomic,copy)NSString *currentURLStirng;
@end
@implementation UIImageView (JQWebImage)
- (void)setImageWithURLString:(NSString *)URLString{
    //如果对同一个cell执行了两次请求操作,取消掉当前正在执行的
    if (![URLString isEqualToString:self.currentURLStirng]&&self.currentURLStirng) {
        [[JQDownloadImageManager sharedManager] cancelDownload:self.currentURLStirng];
    }
    //通过下载管理器去调用相应的下载操作,通过complete 实现block回调
    [[JQDownloadImageManager sharedManager] downloadImageWithURLString:URLString complete:^(UIImage *image) {
        self.image = image;
    }];
    //记录正在下载的url
    self.currentURLStirng = URLString;

}
/**
 *  通过runtime动态添加属性
 */
- (void)setCurrentURLStirng:(NSString *)currentURLStirng{
    objc_setAssociatedObject(self, JQCurrentURLString, currentURLStirng, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)currentURLStirng{
   return  objc_getAssociatedObject(self, JQCurrentURLString);
}
@end

// 下载器
@interface JQDownloadImageManager()
/**
 *  操作缓存
 */
@property (nonatomic,strong)NSMutableDictionary *operationCache;

/**
 *  操作队列(下载队列)全局队列好处:可以控制并发数
 */
@property (nonatomic,strong)NSOperationQueue *queue;
/**
 *  内存缓存,把下载好的图片保存到内存中
 */
@property (nonatomic,strong)NSMutableDictionary *imageCache;
@end
@implementation JQDownloadImageManager

+ (instancetype)sharedManager{
    static dispatch_once_t onceToken;
    //只有一个实例
    static XZHDownloadImageManager *manager;
    dispatch_once(&onceToken, ^{
        manager = [[self alloc]init];
    });
    return manager;
}
/**
 *  通过URLString下载并指定回调操作

 */
- (void)downloadImageWithURLString:(NSString *)URLString complete:(void(^)(UIImage *image))complete{
    if ([self.operationCache objectForKey:URLString]) {
        NSLog(@"正在下载");
        return;
    }
    //开始下载前判断有没有缓存
    if ([self checkCache:URLString]) {
        UIImage *image = [self.imageCache objectForKey:URLString];
        complete(image);
        return;
    }
    //创建下载操作
    //执行异步下载图片
    JQOperation *op = [XZHOperation downloadImageOperationWithURLString:URLString downloadFinished:^(UIImage *image) {
        //下载完成移除操作
        [self.operationCache removeObjectForKey:URLString];
        //回传图片
        complete(image);
    }];
    //把操作添加到队列中
    [self.queue addOperation:op];
    //把操作添加到操作缓存中
    [self.operationCache setObject:op forKey:URLString];
}
/**
 *  取消指定图片的下载操作
 *
 */
- (void)cancelDownload:(NSString *)URLString{
    //通过url拿到操作
    [self.operationCache[URLString] cancel];
    //从缓存中移除
    [self.operationCache removeObjectForKey:URLString];
}

- (BOOL)checkCache:(NSString *)URLStirng{
    //有内存缓存,直接返回。否则从沙盒取,再保存到内存中,最后还是从内存取
    //先判断内存
    if ([self.imageCache objectForKey:URLStirng]) {
        NSLog(@"内存缓存");
        return YES;
    }
    //判断沙盒
    NSString *path = [URLStirng appendCaches];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    if (image) {
        NSLog(@"沙盒缓存");
        //把图片保存到内存缓存中
        [self.imageCache setObject:image forKey:URLStirng];
        return YES;
    }
    return NO;
}
#pragma mark -数据懒加载

- (NSOperationQueue *)queue{
    if (_queue==nil) {
        _queue = [[NSOperationQueue alloc]init];
    }
    return _queue;
}


- (NSMutableDictionary *)operationCache{
    if (_operationCache==nil) {
        _operationCache = [NSMutableDictionary dictionary];
    }
    return _operationCache;
}

- (NSMutableDictionary *)imageCache{
    if (_imageCache == nil) {
        _imageCache = [NSMutableDictionary dictionary];
    }
    return _imageCache;
}
@end


// 下载的操作
@interface JQOperation()
/**
 *  下载图片的URL
 */
@property (nonatomic,copy)NSString *URLString;
/**
 *  下载完成后异步回传下载好的图片
 */
@property (nonatomic,copy)void (^downloadFinished)(UIImage *image);
@end


@implementation JQOperation


/**
 *  封装内部属性,通过提供的类方法传入所需的值赋给相应的属性
 *
 */
+ (instancetype)downloadImageOperationWithURLString:(NSString *)URLStirng downloadFinished:(void(^)(UIImage *image))downloadFinished{
    JQOperation *download = [[self alloc]init];
    download.URLString = URLStirng;
    download.downloadFinished = downloadFinished;
    return download;
}
/**
 *  通过重写main方法来干涉操作的内部,从而实现中断/取消下载
 */
- (void)main{
    //通过包装一个自动释放池可以包装整个操作内存峰值不会太高
    @autoreleasepool {
        //下载图片
        [NSThread sleepForTimeInterval:1];
        NSURL *url = [NSURL URLWithString:self.URLString];
        NSData *data = [NSData dataWithContentsOfURL:url];

        //把二进制数据转换成图片
        UIImage *image = [UIImage imageWithData:data];
        //把图片保存到沙盒中
        if (data) {
            [data writeToFile:(写入的路径) atomically:YES];
        }
        //在关键点(比较耗时的地方)盘点是否在下载期间已经取消下载了
        //取消下载,直接返回
        if(self.isCancelled){
            NSLog(@"已经取消下载");
            return;
        }
        //回到主线程刷新UI
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
          //判断回调block是否已经被赋值
            if (self.downloadFinished) {
                self.downloadFinished(image);
            }
        }];
    }
}
/**
 *  start方法一直都会被调用,无论是否被取消
 */
//- (void)start{
//    
//}
@end

 

posted on 2016-08-20 19:40  久冬不雨  阅读(204)  评论(0编辑  收藏  举报