自定义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. Android开发的16条小经验总结

    Android开发的16条小经验总结,希望对各位搞Android开发的朋友有所帮助. 1. TextView中的getTextSize返回值是以像素(px)为单位的, 而setTextSize()是以 ...

  2. 【java】浅析java组件中的布局管理器

    这篇博文笔者介绍一下java组件中,常用的布局管理器.java组件中的布局方式有好几十种,所有的这些布局管理器都实现了java.awt.LayoutManager接口.接下来笔者介绍一下常用的5种布局 ...

  3. Digital Color Meter 颜色值提取工具

    1.Digital Color Meter 简介 Digital Color Meter 是一款 Mac 自带的颜色值提取工具. 其它下载地址 Digital Color Meter for Mac, ...

  4. 通过Stetho在Chrome上调试Android App

    引 入依赖包 compile 'com.facebook.stetho:stetho:1.3.1' 初始化一下 public class MyApplication extends Applicati ...

  5. [AaronYang原创] 敏捷开发-Jira 6.0.5环境搭建[2]

    基本配置-关卡一(我研究了1.5个小时 AaronYang)   JIRA的设置向导将只显示您安装后第一次JIRA. 一旦你完成了它,你不能再次运行它. 然而,每一个设置在设置向导配置可以通过管理控制 ...

  6. 忙里偷闲写的小例子---读取android根目录下的文件或文件夹

    最近几天真的是各种意义上的忙,忙着考试,还要忙着课程设计,手上又有外包的项目,另一边学校的项目还要搞,自己的东西还在文档阶段,真的是让人想死啊!! 近半个月来,C#这方面的编码比较多,android和 ...

  7. Percona XtraBackup介绍

    Percona XtraBackup开源的.免费的mysql热备软件,可以执行无阻塞备份InnoDB和XtraDB数据库. Percona XtraBackup有以下优点: ·备份快速.可靠 ·备份期 ...

  8. STM8在IAR中Option Byte配置

    转http://www.stmcu.org/module/forum/thread-607140-1-1.html 近期帮客户调试STM8的程序使用到OptionByte配置,在网上查询几乎都是介绍如 ...

  9. stm8 stvd工程头文件包含方式

    方式一:在Include  Files上右键 add files to folder把.h文件添加到该组下, 添加完编译成功之后,下面窗口会多出一个预处理包含路径(若有错误没有编译成功,则看不到) 方 ...

  10. Redis介绍及安装

    官网:https://redis.io/ Redis中文社区:http://www.redis.net.cn/ Redis教程:http://www.redis.net.cn/tutorial/350 ...