自定义NSOperation的话,只是需要将要下载图片的操作下载它的main方法里面,考虑到,图片下载完毕,需要回传到控制器里,这里可以采用block,也可以采用代理的方式实现,我采用的是代理的方式实现的。

重点应该是如何避免同一个url的图片被重复下载?!事实上,可以有这样两个字典,key值是图片的url,value的话,一个字典可以是当前的operation对象,表示,这个url对应的图片正在下载,如果传入图片的url,value不为空的话,说明图片正在下载,那么就不需要再重复下载。另一个字典,可以是存放下载好的图片,也就是常说的缓存,如果一个url取出来的value不为nil,那么这张图片就存在缓存中,不需要再次下载。当然,别忘了设置占位图片~~

这是model的代码:

#import <Foundation/Foundation.h>

@interface ZYApp : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *icon;
@property (nonatomic, copy) NSString *download; + (id)appWithDict:(NSDictionary *)dict;
- (id)initWithDict:(NSDictionary *)dict;
@end #import "ZYApp.h" @implementation ZYApp - (id)initWithDict:(NSDictionary *)dict
{
if (self = [super init]){
[self setValuesForKeysWithDictionary:dict];
// NSLog(@"%@----%@---%@",self.icon,self.name,self.download);
}
return self;
} + (id)appWithDict:(NSDictionary *)dict
{
return [[self alloc] initWithDict:dict];
}
@end

这是自定义的Operation代码:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class ZYDownLoadImageOperation; @protocol ZYDownLoadImageOperationDelegate <NSObject>
@optional
- (void)DownLoadImageOperation:(ZYDownLoadImageOperation *)operation didFinishDownLoadImage:(UIImage *)image;
@end
@interface ZYDownLoadImageOperation : NSOperation
@property (nonatomic, weak) id<ZYDownLoadImageOperationDelegate> delegate;
@property (nonatomic, copy) NSString *url;
@property (nonatomic, strong) NSIndexPath *indexPath;
@end #import "ZYDownLoadImageOperation.h" @implementation ZYDownLoadImageOperation
- (void)main //重写main方法即可
{
@autoreleasepool { //在子线程中,并不会自动添加自动释放池,所以,手动添加,免得MARC的情况下,出现内存泄露的问题
NSURL *DownLoadUrl = [NSURL URLWithString:self.url];
if (self.isCancelled) return; //如果下载操作被取消,那么就无需下面操作了
NSData *data = [NSData dataWithContentsOfURL:DownLoadUrl];
if (self.isCancelled) return;
UIImage *image = [UIImage imageWithData:data];
if (self.isCancelled) return; if ([self.delegate respondsToSelector:@selector(DownLoadImageOperation:didFinishDownLoadImage:)]) {
dispatch_async(dispatch_get_main_queue(), ^{ //回到主线程,更新UI
[self.delegate DownLoadImageOperation:self didFinishDownLoadImage:image];
});
}
}
}
@end

这是控制器代码:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController

@end

#import "ViewController.h"
#import "ZYApp.h"
#import "ZYDownLoadImageOperation.h" @interface ViewController () <UITableViewDataSource, UITableViewDelegate, ZYDownLoadImageOperationDelegate, UIScrollViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView; @property (nonatomic, strong) NSArray *apps; @property (nonatomic, strong) NSOperationQueue *queue; // key:图片的url values: 相对应的operation对象 (判断该operation下载操作是否正在执行,当同一个url地址的图片正在下载,那么不需要再次下载,以免重复下载,当下载操作执行完,需要移除)
@property (nonatomic, strong) NSMutableDictionary *operations; // key:图片的url values: 相对应的图片 (缓存,当下载操作完成,需要将所下载的图片放到缓存中,以免同一个url地址的图片重复下载)
@property (nonatomic, strong) NSMutableDictionary *images;
@end @implementation ViewController #define ZYCellIdentifier @"ZYCellIdentifier"
- (NSArray *)apps
{
if (_apps == nil) {
NSArray *dictArray = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"apps.plist" ofType:nil]];
NSMutableArray *tmpArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
ZYApp *app = [ZYApp appWithDict:dict];
[tmpArray addObject:app];
}
_apps = tmpArray;
}
return _apps;
} - (NSOperationQueue *)queue
{
if (_queue == nil) {
_queue = [[NSOperationQueue alloc] init];
_queue.maxConcurrentOperationCount = 3;
}
return _queue;
} - (NSMutableDictionary *)operations
{
if (_operations == nil) {
_operations = [NSMutableDictionary dictionary];
}
return _operations;
} - (NSMutableDictionary *)images
{
if (_images == nil) {
_images = [NSMutableDictionary dictionary];
}
return _images;
} - (void)viewDidLoad {
[super viewDidLoad]; [self setupView];
} - (void)setupView
{
self.tableView.delegate = self;
self.tableView.dataSource = self;
} - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
} - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ZYCellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ZYCellIdentifier];
}
ZYApp *app = self.apps[indexPath.row];
cell.textLabel.text = app.name;
cell.detailTextLabel.text = app.download;
UIImage *image = self.images[app.icon];
if (image) {
cell.imageView.image = image;
}
else{
cell.imageView.image = [UIImage imageNamed:@"TestMam"];
ZYDownLoadImageOperation *operation = self.operations[app.icon];
if (operation) { //正在下载(可以在里面取消下载) }
else{ //没有在下载
operation = [[ZYDownLoadImageOperation alloc] init];
operation.delegate = self;
operation.url = app.icon;
operation.indexPath = indexPath;
[self.queue addOperation:operation]; //异步下载 self.operations[app.icon] = operation; //加入字典,表示正在执行此次操作
}
}
return cell;
} #pragma mark -- ZYDownLoadImageOperationDelegate
- (void)DownLoadImageOperation:(ZYDownLoadImageOperation *)operation didFinishDownLoadImage:(UIImage *)image
{
[self.operations removeObjectForKey:operation.url]; //下载操作完成,所以把它清掉,表示没有正在下载 if (image){
self.images[operation.url] = image; //下载完毕,放入缓存,免得重复下载 [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone];
} } #pragma mark --- UIScrollViewDelegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.queue setSuspended:YES]; //在拖拽的时候,停止队列下载
} - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
[self.queue setSuspended:NO]; //在停止拖拽的时候,开始队列下载
}
@end

这是此次mode代码github地址:https://github.com/wzpziyi1/CustomOperation

自定义NSOperation下载图片的更多相关文章

  1. (二)scrapy 中如何自定义 pipeline 下载图片

    这里以一个很简单的小爬虫为例,爬取 壹心理 网站的阅读页面第一页的所有文章及其对应的图片,文章页面如下: 创建项目 首先新建一个 scrapy 项目,安装好相关依赖(步骤可参考:scrapy 安装及新 ...

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

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

  3. iOS开发——多线程篇——NSOperation(基于GCD多线程编程),下载图片并合成新图片

    一.NSOperation的基本概念1.简介NSOperation的作用配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperatio ...

  4. iOS多线程自定义operation加载图片 不重复下载图片

    摘要:1:ios通过抽象类NSOperation封装了gcd,让ios的多线程变得更为简单易用:   2:耗时的操作交给子线程来完成,主线程负责ui的处理,提示用户的体验   2:自定义operati ...

  5. Day3-scrapy爬虫下载图片自定义名称

    学习Scrapy过程中发现用Scrapy下载图片时,总是以他们的URL的SHA1 hash值为文件名,如: 图片URL:http://www.example.com/image.jpg 它的SHA1 ...

  6. Scrapy下载图片及自定义分类下载路径

    配置下载图片的流程如下 在items中定义两个属性,image_urls 和images .image_urls是用来存储需要下载的图片url链接,列表类型: 当文件下载完成后会把相关下载信息存入im ...

  7. iOS多线程之9.自定义NSOperation

      本文主要讲如何自定义NSOperation,以及自定义NSOperation的一些注意事项,以下载图片为例. 新建一个类,继承于NSOperation. CustomOperation.h 代码 ...

  8. iOS开发多线程篇—自定义NSOperation

    iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...

  9. iOS多线程编程之自定义NSOperation(转载)

    一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UITableViewController. 1 // ...

随机推荐

  1. Redis 集群_主从配置_哨兵模式

    首先:slaveof 可以在[从]服务器启动一个service服务,直接将[从]服务器定义为[从Redis] redis-server --slaveof <master-ip> < ...

  2. php定时执行sphinx的增量索引

    /** * 每天定时执行的sphinx索引增量更新 * @author guo.jing * 2015-05-08 * @param $indexerArr(执行要更新的索引) */ public f ...

  3. 【C语言】练习2-8

     题目来源:<The C programming language>中的习题P38  练习2-1:  编写一个函数rightrot(x,n),该函数返回将x循环右移(即从最右端移除的位将从 ...

  4. android View未渲染时获得高度

    ViewTreeObserver vto = tv.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new OnGlobalLayoutLis ...

  5. WinRAR破解

    新建记事本文件(txt文件),然后将文件另存为以 rarreg.key 为文件名的文件(当然由于设置的不同,可能出现你保存后的文件为 rarreg.key.txt 没关系,将其重命名,删掉.txt 会 ...

  6. mongoDB 32位 安装包地址

    https://www.mongodb.org/dl/win32/i386 http://downloads.mongodb.org/win32/mongodb-win32-i386-3.2.4-si ...

  7. struts系列:返回json格式的响应

    一.增加依赖库 // https://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin compile group: ' ...

  8. Jedis工具类(含分布式锁的调用和释放)

    个人把工具类分为两部分: 一.连接池部分 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.j ...

  9. [转]Maven - 环境配置

    Maven 是一个基于 Java 的工具,所以要做的第一件事情就是安装 JDK. 系统要求 项目 要求 JDK Maven 3.3 要求 JDK 1.7 或以上Maven 3.2 要求 JDK 1.6 ...

  10. django -- while time zone support is active

    一.先看报错: django 在处理datetime类型的的报错/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site ...