用NSOperation写下载队列

说明

1. 支持缓存机制

2. 图片都是在主线程中加载

3. 文件名用了md5加密

*这东西被人写烂了,但大伙如果对NSOperation不熟悉的话,可以看看本人的实现.

源码

https://github.com/YouXianMing/NSOperationExample

//
// ImageDownloadOperation.h
// NSOperationDownloadImage
//
// Created by YouXianMing on 15/9/7.
// Copyright (c) 2015年 YouXianMing. All rights reserved.
// #import <Foundation/Foundation.h>
@class ImageDownloadOperation; @protocol ImageDownloadOperationDelegate <NSObject> @required
- (void)imageDownloadOperation:(ImageDownloadOperation *)operation data:(NSData *)data; @end @interface ImageDownloadOperation : NSOperation { BOOL _executing;
BOOL _finished;
} /**
* 代理
*/
@property (nonatomic, weak) id <ImageDownloadOperationDelegate> delegate; /**
* 图片地址
*/
@property (nonatomic, strong) NSString *imageUrlString; /**
* 便利构造器
*
* @param urlString 图片地址
* @param delegate 代理
*
* @return 实例对象
*/
+ (instancetype)operationWithImageUrlString:(NSString *)urlString
delegate:(id <ImageDownloadOperationDelegate>)delegate; @end
//
// ImageDownloadOperation.m
// NSOperationDownloadImage
//
// Created by YouXianMing on 15/9/7.
// Copyright (c) 2015年 YouXianMing. All rights reserved.
// #import "ImageDownloadOperation.h"
#import <CommonCrypto/CommonDigest.h> @interface ImageDownloadOperation () @property (nonatomic, strong) NSURLConnection *connection;
@property (nonatomic, strong) NSString *md5String;
@property (nonatomic, strong) NSString *filePathString; @end @implementation ImageDownloadOperation - (void)main { // 验证图片地址是否为空
if (_imageUrlString.length <= ) { [self delegateEventWithData:nil];
[self completeOperation]; return;
} // 生成文件路径
self.md5String = [self MD5HashWithString:_imageUrlString];
self.filePathString = [self pathWithFileName:self.md5String]; // 文件如果存在则直接读取
BOOL exist = [[NSFileManager defaultManager] fileExistsAtPath:self.filePathString isDirectory:nil];
if (exist) { [self delegateEventWithData:[NSData dataWithContentsOfFile:self.filePathString]];
[self completeOperation]; return;
} NSURL *url = [NSURL URLWithString:_imageUrlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self]; // 让线程不结束
do { @autoreleasepool { [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; if (self.isCancelled) { [self completeOperation];
}
} } while (self.isExecuting && self.isFinished == NO);
} #pragma mark - 网络代理
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { } - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { [self writeData:data toPath:self.filePathString];
[self delegateEventWithData:data];
} - (void)connectionDidFinishLoading:(NSURLConnection *)connection { [self completeOperation];
} - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { [self delegateEventWithData:nil];
[self completeOperation];
} #pragma mark -
+ (instancetype)operationWithImageUrlString:(NSString *)urlString
delegate:(id <ImageDownloadOperationDelegate>)delegate { ImageDownloadOperation *operation = [[ImageDownloadOperation alloc] init];
operation.delegate = delegate;
operation.imageUrlString = urlString; return operation;
} #pragma mark -
- (void)completeOperation { [self willChangeValueForKey:@"isFinished"];
[self willChangeValueForKey:@"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:@"isExecuting"];
[self didChangeValueForKey:@"isFinished"];
} - (void)start { if ([self isCancelled]) { [self willChangeValueForKey:@"isFinished"];
_finished = YES;
[self didChangeValueForKey:@"isFinished"]; return;
} [self willChangeValueForKey:@"isExecuting"];
[NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
_executing = YES;
[self didChangeValueForKey:@"isExecuting"];
} - (BOOL)isExecuting { return _executing;
} - (BOOL)isFinished { return _finished;
} - (BOOL)isConcurrent { return YES;
} #pragma mark -
- (NSString *)MD5HashWithString:(NSString *)string { CC_MD5_CTX md5; CC_MD5_Init(&md5);
CC_MD5_Update(&md5, [string UTF8String], (CC_LONG) [string length]); unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(digest, &md5); NSString *s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[], digest[],
digest[], digest[],
digest[], digest[],
digest[], digest[],
digest[], digest[],
digest[], digest[],
digest[], digest[],
digest[], digest[]]; return s;
} - (NSString *)pathWithFileName:(NSString *)name { NSString *path = [NSString stringWithFormat:@"/Documents/%@", name];
return [NSHomeDirectory() stringByAppendingPathComponent:path];
} - (void)delegateEventWithData:(NSData *)data { if (_delegate && [_delegate respondsToSelector:@selector(imageDownloadOperation:data:)]) { dispatch_async(dispatch_get_main_queue(), ^{ [_delegate imageDownloadOperation:self data:data];
});
}
} - (void)writeData:(NSData *)data toPath:(NSString *)path { dispatch_async(dispatch_get_global_queue(, ), ^{ [data writeToFile:path atomically:YES];
});
} @end

细节

用NSOperation写下载队列的更多相关文章

  1. Objective-c 多线程操作 自定义NSOperation 模拟下载

    写在前面 使用多线程下载图片,使用内存缓存和磁盘缓存. 这里只为理解NSOperation及其派生类 真要应用到APP中 请下载成熟的第三方库 效果 下载多张图片时可控制线程并发数 分析 自定义NSO ...

  2. [翻译] 使用开源库 JGDownloadAcceleration 控制下载队列,断点下载,加速下载

    JGDownloadAcceleration 本人对原文进行了翻译,凑合看看,使用心得以后补上 https://github.com/JonasGessner/JGDownloadAccelerati ...

  3. Java语言实现简单FTP软件------>上传下载队列窗口的实现(七)

    1.首先看一下队列窗口的界面 2.看一下上传队列窗口的界面 3.看一下下载队列窗口的界面 4.队列窗口的实现 package com.oyp.ftp.panel.queue; import stati ...

  4. WorldWind源码剖析系列:下载队列类DownloadQueue

    下载队列类DownloadQueue代表具有优先级的下载队列,该类的存储下载请求的数组链表专门按一定的优先级来存储下载请求的.该类的类图如下. 下载队列类DownloadQueue各个字段的含义说明如 ...

  5. 手写阻塞队列(Condition实现)

    自己实现阻塞队列的话可以采用Object下的wait和notify方法,也可以使用Lock锁提供的Condition来实现,本文就是自己手撸的一个简单的阻塞队列,部分借鉴了JDK的源码.Ps:最近看面 ...

  6. Netty源码分析第7章(编码器和写数据)---->第3节: 写buffer队列

    Netty源码分析七章: 编码器和写数据 第三节: 写buffer队列 之前的小节我们介绍过, writeAndFlush方法其实最终会调用write和flush方法 write方法最终会传递到hea ...

  7. PHP怎样写延时队列(定时器)

    背景 PHP没有定时器,依托的都是crontab这样的系统工具,也没有go中defer这样的延时方法,本文介绍几种PHP写延时队列的几种姿势. 延时队列的定义 普通的队列是先进先出,但是延时队列并不是 ...

  8. 弹出窗口a标签写下载,再弹出窗口

    如果这个窗口是弹出出口,直接<a href="">点击下载<a>是不行的,得用js这样写,弹出并关闭,不然会回到首页,如果没有定义首页会报错,<a h ...

  9. 三 基于Java数组手写循环队列

    Code: package dataStucture2.stackandqueue; /** * 手写循环队列 * * @param <E> */ public class MyLoopQ ...

随机推荐

  1. Linux-(which,whereis,locate,find)

    我们经常在linux要查找某个文件,但不知道放在哪里了,可以使用下面的一些命令来搜索: which  查看可执行文件的位置. whereis 查看文件的位置. locate   配合数据库查看文件位置 ...

  2. C语言中的条件编译

    通常情况,我们想让程序选择性地执行,多会使用分支语句,比如if-else 或者switch-case 等.但有些时候,可能在程序的运行过程中,某个分支根本不会执行. 比如我们要写一个跨平台项目,要求项 ...

  3. 移动端H5适配方法(盒子+图片+文字)

    一.怎么让H5页面适应手机 a.利用meta标签 <meta name="viewport" content="width=device-width,initial ...

  4. [转]MVC中几种常用ActionResult

    本文转自:http://www.cnblogs.com/xielong/p/5940535.html 一.定义 MVC中ActionResult是Action的返回结果.ActionResult 有多 ...

  5. 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(四)——对 run.py 的调整

    使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(一)——创建应用 使用 Flask 框架写用户登录功能的Demo时碰到的各种坑(二)——使用蓝图功能进行模块化 使用 Flask 框架写用 ...

  6. ABP学习入门系列(五)(展示实现增删改查)

    大致要实现的 效果如下 1,添加Controller(用到的X.PagedList 注意到nuget添加) using System.Web.Mvc; using Abp.Application.Se ...

  7. C语言读取配置文件

    自从大学学完C之后,就再也没用过它了, 在网上找代码,七拼八凑之后,终于成形~~勉强能用,不喜勿喷,^_^! int GetValue(const wchar_t *key, wchar_t *val ...

  8. hdu 1023 卡特兰数《 大数》java

    Train Problem II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  9. WPF流程图制作系列相关基础二

       我们现在知道 thumb ,可以让用户自行拖动其在 canvas上移动,在这个而基础上 我们可以试着往流程图方向靠近一下. 我们知道,流程图,都是一个一个的流程块,然后用线连起来的,这一个一个的 ...

  10. 小tip:FireFox下文本框/域百分比padding bug解决——张鑫旭

    一.问题描述 我是流体布局控,经常会遇到文本框以及文本域宽度100%自适应显示的情况. 如下效果图: 在窄屏下,上面的文本框宽度也要跟着外部宽度变小. 难点对于文本框或者文本域,光标最好距离左侧边缘有 ...