自定义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 // ...
随机推荐
- XP、Windows7下自动关机vbs脚本,使用windows计划任务+vbs脚本在XP、Windows7下实现定时自动关机
VBScript(Microsoft Visual Basic Script Edition).,微软公司可视化BASIC脚本版). 正如其字面所透露的信息, VBS(VBScript的进一步简写)是 ...
- HDU 2492 Ping pong (数状数组)
Ping pong Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- 【Visual Studio】如何在VS 2012中打印变量值到输出窗口
1.在调试程序时,想要输出某个变量的值到vs的输出窗口,而不是通过添加断点,每次调试时,一步一步的看变量的值,很麻烦,用console.writeline(str);是不行的,这个命令只能用在控制台应 ...
- IDEA 配置Gradle编译工具
下载解压自己需要的gradle版本:https://gradle.org/releases/(免安装) 配置环境变量 打开命令窗口,输入 gradle -v IDEA配置gradle:file-> ...
- python练习笔记——组合恒等式
排列组合结合恒等式 已知从n个物品中取出m个,则存在一个组合恒等式. C(n, m)=C(n, n-m)=C(n-1, m-1)+C(n-1,m) 其中C(n,0) = 1 求:从5取3 和 10 取 ...
- Android应用截图方法
在Android应用开发过程中,可能会遇到需要对整个界面或者某一部分进行截图的需求.Android中对View的截图也有很多中方式: 使用DrawingCache 直接调用View.draw Draw ...
- 探讨android更新UI的几种方法
作为IT新手,总以为只要有时间,有精力,什么东西都能做出来.这种念头我也有过,但很快就熄灭了,因为现实是残酷的,就算一开始的时间和精力非常充足,也会随着项目的推进而逐步消磨殆尽.我们会发现,自己越来越 ...
- Linux中断概述
中断和异常 1.1中断的由来及实质 Linux内核要管理计算机上的硬件设备,首先要和他们通信.而处理器的速度跟外围硬件设备的速度往往不在一个数量级上,因此,如果内核采取让处理器向硬件发出一个请求,然后 ...
- mmap映射文件至内存( 实现 共享内存 与 文件的另类访问 )
Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对文件的读取和修改, 先来看一下mmap的函数声明: 头文件: < ...
- Android Framework中的线程Thread及它的threadLoop方法
当初跟踪Camera的代码中的时候一直追到了HAL层,而在Framework中的代码看见了许很多多的Thread.它们普遍的特点就是有一个threadLoop方法.依照字面的意思应该是这个线程能够循环 ...