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

一、实现一个简单的tableView显示效果

实现效果展示:

代码示例(使用以前在主控制器中进行业务处理的方式)

1.新建一个项目,让控制器继承自UITableViewController。

 //
// YYViewController.h
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import <UIKit/UIKit.h> @interface YYViewController : UITableViewController @end

2.处理storyboard中得界面,如下:

3.根据plist文件,字典转模型

新建一个类,继承自NSObject,作为数据的模型

YYappModel.h文件

 //
// YYappModel.h
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import <Foundation/Foundation.h> @interface YYappModel : NSObject
/**
*应用名称
*/
@property(nonatomic,copy)NSString *name;
/**
* 应用图片
*/
@property(nonatomic,copy)NSString *icon;
/**
* 应用的下载量
*/
@property(nonatomic,copy)NSString *download; +(instancetype)appModelWithDict:(NSDictionary *)dict;
-(instancetype)initWithDict:(NSDictionary *)dict;
@end

YYappModel.m文件

 //
// YYappModel.m
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import "YYappModel.h" @implementation YYappModel -(instancetype)initWithDict:(NSDictionary *)dict
{
if (self=[super init]) {
[self setValuesForKeysWithDictionary:dict];
}
return self;
} //工厂方法
+(instancetype)appModelWithDict:(NSDictionary *)dict
{
return [[self alloc]initWithDict:dict];
}
@end

主控制器中得逻辑控制部分,YYViewController.m文件

 //
// YYViewController.m
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import "YYViewController.h"
#import "YYappModel.h" @interface YYViewController ()
@property(nonatomic,strong)NSArray *apps; @end @implementation YYViewController
#pragma mark- 懒加载
-(NSArray *)apps
{
if (_apps==nil) {
NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; //字典转模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
} #pragma mark-数据源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
} -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"ID";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
YYappModel *app=self.apps[indexPath.row];
cell.textLabel.text=app.name;
cell.detailTextLabel.text=app.download; //下载图片数据
NSLog(@"加载图片数据---%@", [NSThread currentThread]);
NSURL *url=[NSURL URLWithString:app.icon];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *imgae=[UIImage imageWithData:data];
cell.imageView.image=imgae;
NSLog(@"完成显示");
return cell;
} @end

打印查看:

二、自定义NSOperation

说明:上面的下载图片数据部分是一个非常耗时的操作,这个操作任务在主线程完成,会严重的影响到用户体验,造成UI卡的现象。下面通过自定义NSOperation,新开线程,让加载图片的任务异步执行。

1.通过代理

在上面的基础上,新建一个类,让其继承自NSOperation。

YYdownLoadOperation.h文件

 //
// YYdownLoadOperation.h
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import <Foundation/Foundation.h> #pragma mark-设置代理和代理方法
@class YYdownLoadOperation;
@protocol YYdownLoadOperationDelegate <NSObject>
-(void)downLoadOperation:(YYdownLoadOperation*)operation didFishedDownLoad:(UIImage *)image;
@end @interface YYdownLoadOperation : NSOperation
@property(nonatomic,copy)NSString *url;
@property(nonatomic,strong)NSIndexPath *indexPath;
@property(nonatomic,strong)id <YYdownLoadOperationDelegate> delegate;
@end

YYdownLoadOperation.m文件

 //
// YYdownLoadOperation.m
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import "YYdownLoadOperation.h" @implementation YYdownLoadOperation
-(void)main
{
NSURL *url=[NSURL URLWithString:self.url];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *imgae=[UIImage imageWithData:data]; NSLog(@"--%@--",[NSThread currentThread]);
//图片下载完毕后,通知代理
if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) {
dispatch_async(dispatch_get_main_queue(), ^{//回到主线程,传递数据给代理对象
[self.delegate downLoadOperation:self didFishedDownLoad:imgae];
});
}
}
@end

主控制器中的业务逻辑:

 //
// YYViewController.m
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import "YYViewController.h"
#import "YYappModel.h"
#import "YYdownLoadOperation.h" @interface YYViewController ()<YYdownLoadOperationDelegate>
@property(nonatomic,strong)NSArray *apps;
@property(nonatomic,strong)NSOperationQueue *queue; @end @implementation YYViewController
#pragma mark- 懒加载apps
-(NSArray *)apps
{
if (_apps==nil) {
NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; //字典转模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
} #pragma mark-懒加载queue
-(NSOperationQueue *)queue
{
if (_queue==Nil) {
_queue=[[NSOperationQueue alloc]init];
//设置最大并发数为3
_queue.maxConcurrentOperationCount=;
}
return _queue;
} #pragma mark-数据源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"ID";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
YYappModel *app=self.apps[indexPath.row];
cell.textLabel.text=app.name;
cell.detailTextLabel.text=app.download; //下载图片数据
// NSLog(@"加载图片数据---%@", [NSThread currentThread]);
// NSURL *url=[NSURL URLWithString:app.icon];
// NSData *data=[NSData dataWithContentsOfURL:url];
// UIImage *imgae=[UIImage imageWithData:data];
// cell.imageView.image=imgae; //创建一个OPeration对象
YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init];
operation.url=app.icon;
operation.indexPath=indexPath;
operation.delegate=self; //把操作对象添加到队列中在去
[self.queue addOperation:operation]; // NSLog(@"完成显示");
return cell;
}
-(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
{
//返回图片数据给每行对应的cell的imageview.image
//取出tableview中indexPath这一行对应的cell
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:operation.indexPath];
//显示图片
cell.imageView.image=image;
// NSLog(@"cell--index--%@---%@",operation.indexPath,[NSThread currentThread]);
//一定要刷新表格
[self.tableView reloadData];
NSLog(@"--%@--",[NSThread currentThread]); }
@end

说明:通过打印可以发现上面的代码存在很大的问题。

问题1:需要保证一个url对应一个operation对象。

问题2:下载完需要移除。移除执行完毕的操作。

问题3:保证一个url对应一个image。
下面对主控制器中得代码进行改进:
 //
// YYViewController.m
// 01-自定义Operation
//
// Created by apple on 14-6-26.
// Copyright (c) 2014年 itcase. All rights reserved.
// #import "YYViewController.h"
#import "YYappModel.h"
#import "YYdownLoadOperation.h" @interface YYViewController ()<YYdownLoadOperationDelegate>
@property(nonatomic,strong)NSArray *apps;
@property(nonatomic,strong)NSOperationQueue *queue;
@property(nonatomic,strong)NSMutableDictionary *operations;
@property(nonatomic,strong)NSMutableDictionary *images; @end @implementation YYViewController
#pragma mark- 懒加载apps
-(NSArray *)apps
{
if (_apps==nil) {
NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
NSArray *tempArray=[NSArray arrayWithContentsOfFile:path]; //字典转模型
NSMutableArray *array=[NSMutableArray array];
for (NSDictionary *dict in tempArray) {
YYappModel *app=[YYappModel appModelWithDict:dict];
[array addObject:app];
}
_apps=array;
}
return _apps;
} #pragma mark-懒加载queue
-(NSOperationQueue *)queue
{
if (_queue==Nil) {
_queue=[[NSOperationQueue alloc]init];
//设置最大并发数为3
_queue.maxConcurrentOperationCount=;
}
return _queue;
} #pragma mark-懒加载operations
-(NSMutableDictionary *)operations
{
if (_operations==Nil) {
_operations=[NSMutableDictionary dictionary];
}
return _operations;
} #pragma mark-懒加载images
-(NSMutableDictionary *)images
{
if (_images==Nil) {
_images=[NSMutableDictionary dictionary];
}
return _images;
} #pragma mark-数据源方法
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.apps.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *ID=@"ID";
UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
if (cell==nil) {
cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}
YYappModel *app=self.apps[indexPath.row];
cell.textLabel.text=app.name;
cell.detailTextLabel.text=app.download; //保证一个url对应一个image对象
UIImage *image=self.images[app.icon];
if (image) {//缓存中有图片
cell.imageView.image=image;
}else // 缓存中没有图片,得下载
{
//先设置一张占位图片
cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];
YYdownLoadOperation *operation=self.operations[app.icon];
if (operation) {//正在下载
//什么都不做
}else //当前没有下载,那就创建操作
{
operation=[[YYdownLoadOperation alloc]init];
operation.url=app.icon;
operation.indexPath=indexPath;
operation.delegate=self;
[self.queue addOperation:operation];//异步下载
self.operations[app.icon]=operation;
}
} return cell;
}
-(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
{
//1.移除执行完毕的操作
[self.operations removeObjectForKey:operation.url]; //2.将图片放到缓存中
self.images[operation.url]=image; //3.刷新表格(只刷新下载的那一行) [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]); }
@end

打印查看:

iOS开发多线程篇—自定义NSOperation的更多相关文章

  1. iOS开发多线程篇 09 —NSOperation简单介绍

    iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...

  2. iOS开发多线程篇 10 —NSOperation基本操作

    iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. ...

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

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

  4. iOS开发多线程篇—NSOperation简单介绍

    iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...

  5. iOS开发多线程篇—NSOperation基本操作

    iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. ...

  6. iOS开发多线程篇—多线程简单介绍

    iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...

  7. iOS开发多线程篇—线程安全

    iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...

  8. iOS 开发多线程篇—GCD的常见用法

    iOS开发多线程篇—GCD的常见用法 一.延迟执行 1.介绍 iOS常见的延时执行有2种方式 (1)调用NSObject的方法 [self performSelector:@selector(run) ...

  9. iOS开发多线程篇—创建线程

    iOS开发多线程篇—创建线程 一.创建和启动线程简单说明 一个NSThread对象就代表一条线程 创建.启动线程 (1) NSThread *thread = [[NSThread alloc] in ...

随机推荐

  1. BJFU 1015

    描述 数字具有神奇的魔力,神奇到ben想把所有数字全部保存起来.于是他设想了如下的保存方法.假设有一张无限大的纸板,将所有自然数(不包括0)按如下顺序排列书写在纸板上保存:1 2 6 7  15  1 ...

  2. zTree插件之多选下拉菜单代码

    zTree插件之多选下拉菜单代码 css和js <!--ztree树结构--> <link rel="stylesheet" type="text/cs ...

  3. Centos6.5 安装 RabbitMQ3.6.1

    Centos6.5 安装 RabbitMQ3.6.1 个人安装RabbitMQ总结: 安装编译工具 yum -y install make gcc gcc-c++ kernel-devel m4 nc ...

  4. mysql查询优化器的提示(hit)

    如果对优化器选择的执行计划不满意,可以使用优化器提供的几个提示来控制最终的执行计划,关于每个提示的具体用法,建议直接阅读官方手册,一些提示和版本有直接关系,可以使用的一些提示如下: high_prio ...

  5. IIS 7 应用程序池自动回收关闭的解决方案

    如果你正在做ASP.NET,那肯定会用到IIS 如果你想在ASP.NET Application中加入某个定时任务,那想必一定是用一个线程在不停地做定时计算 那假设我们在自己的ASP.NET应用程序中 ...

  6. Designing a CSS based template

    http://veerle-v2.duoh.com/blog/comments/designing_a_css_based_template_part_i/

  7. centos6.6编译安装lnmp系列之PHP

    简介: 环境:虚拟机+centos6.6 在百度云盘里面我分享的安装软件包,包含LNMP系列软件. http://pan.baidu.com/s/1gdvnimv 1.安装前配置: 关闭selinux ...

  8. [问题2014S03] 复旦高等代数II(13级)每周一题(第三教学周)

    [问题2014S03]  设 \(A\in M_n(\mathbb R)\) 是非异阵并且 \(A\) 的 \(n\) 个特征值都是实数. 若 \(A\) 的所有 \(n-1\) 阶主子式之和等于零, ...

  9. HDU1848 Fibonacci again and again SG函数

    Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

  10. Exchange Server 2013就地存档

    9.1就地存档 就地存档有助于重新获得对组织邮件数据的控制,而无需个人存储 (.pst) 文件,并且允许用户在可通过 Microsoft Outlook 2010及更高版本和 Microsoft Of ...