用NSOperation写下载队列

说明

1. 支持缓存机制

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

3. 文件名用了md5加密

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

源码

https://github.com/YouXianMing/NSOperationExample

  1. //
  2. // ImageDownloadOperation.h
  3. // NSOperationDownloadImage
  4. //
  5. // Created by YouXianMing on 15/9/7.
  6. // Copyright (c) 2015年 YouXianMing. All rights reserved.
  7. //
  8.  
  9. #import <Foundation/Foundation.h>
  10. @class ImageDownloadOperation;
  11.  
  12. @protocol ImageDownloadOperationDelegate <NSObject>
  13.  
  14. @required
  15. - (void)imageDownloadOperation:(ImageDownloadOperation *)operation data:(NSData *)data;
  16.  
  17. @end
  18.  
  19. @interface ImageDownloadOperation : NSOperation {
  20.  
  21. BOOL _executing;
  22. BOOL _finished;
  23. }
  24.  
  25. /**
  26. * 代理
  27. */
  28. @property (nonatomic, weak) id <ImageDownloadOperationDelegate> delegate;
  29.  
  30. /**
  31. * 图片地址
  32. */
  33. @property (nonatomic, strong) NSString *imageUrlString;
  34.  
  35. /**
  36. * 便利构造器
  37. *
  38. * @param urlString 图片地址
  39. * @param delegate 代理
  40. *
  41. * @return 实例对象
  42. */
  43. + (instancetype)operationWithImageUrlString:(NSString *)urlString
  44. delegate:(id <ImageDownloadOperationDelegate>)delegate;
  45.  
  46. @end
  1. //
  2. // ImageDownloadOperation.m
  3. // NSOperationDownloadImage
  4. //
  5. // Created by YouXianMing on 15/9/7.
  6. // Copyright (c) 2015年 YouXianMing. All rights reserved.
  7. //
  8.  
  9. #import "ImageDownloadOperation.h"
  10. #import <CommonCrypto/CommonDigest.h>
  11.  
  12. @interface ImageDownloadOperation ()
  13.  
  14. @property (nonatomic, strong) NSURLConnection *connection;
  15. @property (nonatomic, strong) NSString *md5String;
  16. @property (nonatomic, strong) NSString *filePathString;
  17.  
  18. @end
  19.  
  20. @implementation ImageDownloadOperation
  21.  
  22. - (void)main {
  23.  
  24. // 验证图片地址是否为空
  25. if (_imageUrlString.length <= ) {
  26.  
  27. [self delegateEventWithData:nil];
  28. [self completeOperation];
  29.  
  30. return;
  31. }
  32.  
  33. // 生成文件路径
  34. self.md5String = [self MD5HashWithString:_imageUrlString];
  35. self.filePathString = [self pathWithFileName:self.md5String];
  36.  
  37. // 文件如果存在则直接读取
  38. BOOL exist = [[NSFileManager defaultManager] fileExistsAtPath:self.filePathString isDirectory:nil];
  39. if (exist) {
  40.  
  41. [self delegateEventWithData:[NSData dataWithContentsOfFile:self.filePathString]];
  42. [self completeOperation];
  43.  
  44. return;
  45. }
  46.  
  47. NSURL *url = [NSURL URLWithString:_imageUrlString];
  48. NSURLRequest *request = [NSURLRequest requestWithURL:url];
  49. self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
  50.  
  51. // 让线程不结束
  52. do {
  53.  
  54. @autoreleasepool {
  55.  
  56. [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
  57.  
  58. if (self.isCancelled) {
  59.  
  60. [self completeOperation];
  61. }
  62. }
  63.  
  64. } while (self.isExecuting && self.isFinished == NO);
  65. }
  66.  
  67. #pragma mark - 网络代理
  68. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
  69.  
  70. }
  71.  
  72. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
  73.  
  74. [self writeData:data toPath:self.filePathString];
  75. [self delegateEventWithData:data];
  76. }
  77.  
  78. - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
  79.  
  80. [self completeOperation];
  81. }
  82.  
  83. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
  84.  
  85. [self delegateEventWithData:nil];
  86. [self completeOperation];
  87. }
  88.  
  89. #pragma mark -
  90. + (instancetype)operationWithImageUrlString:(NSString *)urlString
  91. delegate:(id <ImageDownloadOperationDelegate>)delegate {
  92.  
  93. ImageDownloadOperation *operation = [[ImageDownloadOperation alloc] init];
  94. operation.delegate = delegate;
  95. operation.imageUrlString = urlString;
  96.  
  97. return operation;
  98. }
  99.  
  100. #pragma mark -
  101. - (void)completeOperation {
  102.  
  103. [self willChangeValueForKey:@"isFinished"];
  104. [self willChangeValueForKey:@"isExecuting"];
  105. _executing = NO;
  106. _finished = YES;
  107. [self didChangeValueForKey:@"isExecuting"];
  108. [self didChangeValueForKey:@"isFinished"];
  109. }
  110.  
  111. - (void)start {
  112.  
  113. if ([self isCancelled]) {
  114.  
  115. [self willChangeValueForKey:@"isFinished"];
  116. _finished = YES;
  117. [self didChangeValueForKey:@"isFinished"];
  118.  
  119. return;
  120. }
  121.  
  122. [self willChangeValueForKey:@"isExecuting"];
  123. [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
  124. _executing = YES;
  125. [self didChangeValueForKey:@"isExecuting"];
  126. }
  127.  
  128. - (BOOL)isExecuting {
  129.  
  130. return _executing;
  131. }
  132.  
  133. - (BOOL)isFinished {
  134.  
  135. return _finished;
  136. }
  137.  
  138. - (BOOL)isConcurrent {
  139.  
  140. return YES;
  141. }
  142.  
  143. #pragma mark -
  144. - (NSString *)MD5HashWithString:(NSString *)string {
  145.  
  146. CC_MD5_CTX md5;
  147.  
  148. CC_MD5_Init(&md5);
  149. CC_MD5_Update(&md5, [string UTF8String], (CC_LONG) [string length]);
  150.  
  151. unsigned char digest[CC_MD5_DIGEST_LENGTH];
  152. CC_MD5_Final(digest, &md5);
  153.  
  154. NSString *s = [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
  155. digest[], digest[],
  156. digest[], digest[],
  157. digest[], digest[],
  158. digest[], digest[],
  159. digest[], digest[],
  160. digest[], digest[],
  161. digest[], digest[],
  162. digest[], digest[]];
  163.  
  164. return s;
  165. }
  166.  
  167. - (NSString *)pathWithFileName:(NSString *)name {
  168.  
  169. NSString *path = [NSString stringWithFormat:@"/Documents/%@", name];
  170. return [NSHomeDirectory() stringByAppendingPathComponent:path];
  171. }
  172.  
  173. - (void)delegateEventWithData:(NSData *)data {
  174.  
  175. if (_delegate && [_delegate respondsToSelector:@selector(imageDownloadOperation:data:)]) {
  176.  
  177. dispatch_async(dispatch_get_main_queue(), ^{
  178.  
  179. [_delegate imageDownloadOperation:self data:data];
  180. });
  181. }
  182. }
  183.  
  184. - (void)writeData:(NSData *)data toPath:(NSString *)path {
  185.  
  186. dispatch_async(dispatch_get_global_queue(, ), ^{
  187.  
  188. [data writeToFile:path atomically:YES];
  189. });
  190. }
  191.  
  192. @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. mysql RC下不存在则插入

    mysql版本:5.7 目的:在RC下,name列上仅有key索引,并发插入name时不出现重复数据 RC不加gap lock,并且复合select语句是不加锁的快照读,导致两个事务同时进行都可插入, ...

  2. koa2开发入门

    一.koa2入门 1.创建koa2工程 首先,我们创建一个目录hello-koa并作为工程目录用VS Code打开.然后,我们创建app.js,输入以下代码: // 导入koa,和koa 1.x不同, ...

  3. jqGrid随窗口大小变化自适应大小-转

    第一种: jqGrid随窗口大小变化自适应宽度 $(function(){ $(window).resize(function(){ $("#listId").setGridWid ...

  4. 使用Quartz.net来执行定时任务

    Quartz.net使用方法:http://www.cnblogs.com/lizichao1991/p/5707604.html 最近,项目中需要执行一个计划任务,组长就让我了解一下Quartz.n ...

  5. json list数据递归生成树状层级JSON

    <!DOCTYPE html> <html> <head> <script> var data=[ {"id":"aaa& ...

  6. Java线程池,你了解多少?

    一.前言 随着业务的发展,单线程已经远远不能满足,随即就有多线程的出现.多线程虽然能解决单线程解决不了的事情,但是它也会给你带来额外的问题.比如成千上万甚至上百万的线程时候,你系统就会出现响应延迟.卡 ...

  7. Node.js数据流Stream之Duplex流和Transform流

    Duplex流一个很好的例子是TCP套接字连接.需要实现_read(size)和_Write(data,encoding,callback)方法. var stream = require('stre ...

  8. unity简单动画实现

    1:创建一个Sprite Render (player)的动画对象并添加脚本Player,点击主菜单“Window(视窗)→Animation(动画窗口)”Animation面板(选中需要动画的对象) ...

  9. WPF popup被截断的原因和修改方法

    原因:wpf里 popup不能超过屏幕75%的面积,不知道为什么要这么设置? 修改方法: private void SetPopupScreen() { Rect rtWnd = , , gridMa ...

  10. 不用中间变量,交换a、b值

    如果要交换a.b之间的值,一般的做法是: tmp=a;a=b;b=tmp;这种方法不得不使用一个临时变量. 从网上学来一个方法,可以不用使用临时变量: a^=b^=a^=b; 这样计算之后,就可以交换 ...