zoukankan      html  css  js  c++  java
  • 第三篇、简单的图片下载器

    第一种:

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

    实现原理:

      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
  • 相关阅读:
    python 面向对象编程的三大特征之一 多态
    python 访问控制
    python 面向对象编程的三大特征之一 继承
    朱兆祺教你如何攻破C语言学习、笔试与机试的难点
    如何画好流程图
    2013年个人计划
    30天敏捷结果(1):总体认识Getting Result敏捷方法
    每天一个linux命令目录
    国嵌C语言学习
    【head first python】1.初识python 人人都爱列表
  • 原文地址:https://www.cnblogs.com/HJQ2016/p/5791096.html
Copyright © 2011-2022 走看看