自定义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. 入门程序,hello world

    RabbitMQ是消息代理.从本质上说,它接受来自生产者的信息,并将它们传递给消费者.在两者之间,它可以根据你给它的路由,缓冲规则进行传递消息. 一.专业术语 1. 生产者: 在现实生活中就好比制造商 ...

  2. Win7 U盘安装Ubuntu16.04 双系统详细教程(方法一)

    主要分为以下几步: 一. 下载Ubuntu 16.04镜像软件: 二. 制作U盘启动盘使用ultraISO: 三. 安装Ubuntu系统: 四. 用EasyBCD 创建启动系统启动引导: (根据个人情 ...

  3. No package的问题解决

    更新pecl扩展 yum  install epel-release  //扩展包更新包yum  update //更新yum源

  4. 【java】解析java中的数组

    目录结构: contents structure [+] 一维数组 1,什么是一维数组 2,声明一维数组的三种方式 二维数组 1,什么是二维数组 2,声明二维数组的3种方式 3,二维数组的遍历示例 数 ...

  5. Postgresql 正则表达式

    在postgresql中使用正则表达式时需要使用关键字“~”,以表示该关键字之前的内容需匹配之后的正则表达式,若匹配规则不需要区分大小写,可以使用组合关键字“~*”: 相反,若需要查询不匹配这则表达式 ...

  6. 使用SQL Server发送邮件时遇到的诡异事件

    最近公司要实现一个邮件群发的功能,因此设计时就考虑用SQL Server的邮件发送功能直接推送邮件算了. 可是在实现的过程中,邮件内容中有一个表格的内容要展现,于是就编排了一个表格来实现. 具体实现如 ...

  7. Oracle - 层次查询

    如果表中含有层次数据,可以通过使用层次查询有序地查看层次数据. 语法: condition:指一个或多个表达式和逻辑(布尔)运算符的组合,并返回TRUE.FALSE或UNKNOWNstart with ...

  8. process credentials(一)

    一.介绍 当linux系统中的一个进程运行起来的时候,总是要访问系统的资源,访问文件或者向其他的进程发送信号.系统是否允许其进行这些操作?系统是根据什么来判断该进程的权限?这些问题是和进程信任状(pr ...

  9. php网站被挂木马修复方法总结

    在linux中我们可以使用命令来搜查木马文件,到代码安装目录执行下面命令 代码如下 复制代码 find ./ -iname "*.php" | xargs grep -H -n & ...

  10. [转]JSON Web Token - 在Web应用间安全地传递信息

    JSON Web Token(JWT)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. 让我们来假想一下一个场景.在A用户关注了B用户的时候,系统发邮件给B用户, ...