自定义NSOperation下载图片
自定义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下载图片的更多相关文章
- (二)scrapy 中如何自定义 pipeline 下载图片
这里以一个很简单的小爬虫为例,爬取 壹心理 网站的阅读页面第一页的所有文章及其对应的图片,文章页面如下: 创建项目 首先新建一个 scrapy 项目,安装好相关依赖(步骤可参考:scrapy 安装及新 ...
- Objective-c 多线程操作 自定义NSOperation 模拟下载
写在前面 使用多线程下载图片,使用内存缓存和磁盘缓存. 这里只为理解NSOperation及其派生类 真要应用到APP中 请下载成熟的第三方库 效果 下载多张图片时可控制线程并发数 分析 自定义NSO ...
- iOS开发——多线程篇——NSOperation(基于GCD多线程编程),下载图片并合成新图片
一.NSOperation的基本概念1.简介NSOperation的作用配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperatio ...
- iOS多线程自定义operation加载图片 不重复下载图片
摘要:1:ios通过抽象类NSOperation封装了gcd,让ios的多线程变得更为简单易用: 2:耗时的操作交给子线程来完成,主线程负责ui的处理,提示用户的体验 2:自定义operati ...
- Day3-scrapy爬虫下载图片自定义名称
学习Scrapy过程中发现用Scrapy下载图片时,总是以他们的URL的SHA1 hash值为文件名,如: 图片URL:http://www.example.com/image.jpg 它的SHA1 ...
- Scrapy下载图片及自定义分类下载路径
配置下载图片的流程如下 在items中定义两个属性,image_urls 和images .image_urls是用来存储需要下载的图片url链接,列表类型: 当文件下载完成后会把相关下载信息存入im ...
- iOS多线程之9.自定义NSOperation
本文主要讲如何自定义NSOperation,以及自定义NSOperation的一些注意事项,以下载图片为例. 新建一个类,继承于NSOperation. CustomOperation.h 代码 ...
- iOS开发多线程篇—自定义NSOperation
iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...
- iOS多线程编程之自定义NSOperation(转载)
一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UITableViewController. 1 // ...
随机推荐
- 转:Spring Cache抽象详解
缓存简介 缓存,我的理解是:让数据更接近于使用者:工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存):缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/I ...
- Fedora下使用minicom及USB串口线
一.minicom Fedora不像以前的RedHat,不能直接输入minicom回车,因为在目录/dev/下面没有modem这个子目录,而minicom的运行默认是有这个目录的,所以直接敲是不行的. ...
- 网络编程学习笔记一:Socket编程
“一切皆Socket!” 话虽些许夸张,但是事实也是,现在的网络编程几乎都是用的socket. ——有感于实际编程和开源项目研究. 我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览 ...
- 创建 maven maven-archetype-quickstart 项目抱错问题解决方法
问题: eclipse装m2eclipse的时候装完后创建项目的时候报错: Unable to create project from archetype org.apache.maven.arche ...
- CentOS7下解决ifconfig command not found
原文地址:https://blog.csdn.net/ryu2003/article/details/78492127 注:本办法仅限于可联网的机器,即在安装时设置了IP地址和DNS可正常上网. 解决 ...
- ELK 5.X版本遇到的坑
一.Kafka ->logstash ->elasticsearch logstash 5.X以上版本不兼容5.x以下版本,因此在升级logstash时会遇到很多坑.首先是配置的变化 ...
- ORACLE在线切换undo表空间
切换undo的一些步骤和基本原则 原文:http://www.xifenfei.com/3367.html 查看原undo相关参数 SHOW PARAMETER UNDO; 创建新undo空间 cre ...
- 如何控制android系统中NavigationBar 的显示与隐藏
我们使用的大多数android手机上的Home键,返回键以及menu键都是实体触摸感应按键.如果你用Google的Nexus4或Nexus5话,你会发现它们并没有实体按键或触摸感应按键,取而代之的是在 ...
- 20本最好的Linux免费书籍
前些天Neo推荐了一个网站有<超过100本的linux免费书籍>,这里,我也向大家推荐20本最好的Linux免费书籍,当然,也是英文版的. 1. Ubuntu Pocket Guide a ...
- MySQL经常使用技巧
建表 每一个表都有一个id字段,最好为UNSIGNED.如 INT(9) UNSIGNED NOT NULL 在表使用一段时间后,使用PROCEDURE ANALYSE得到建议,如select * f ...