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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

实现效果展示:

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

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

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

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYViewController.h
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import <UIKit/UIKit.h>
10
11 @interface YYViewController : UITableViewController
12
13 @end
iOS开发多线程篇 11 —自定义NSOperation

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

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

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

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

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

YYappModel.h文件

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYappModel.h
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 @interface YYappModel : NSObject
12 /**
13 *应用名称
14 */
15 @property(nonatomic,copy)NSString *name;
16 /**
17 * 应用图片
18 */
19 @property(nonatomic,copy)NSString *icon;
20 /**
21 * 应用的下载量
22 */
23 @property(nonatomic,copy)NSString *download;
24
25 +(instancetype)appModelWithDict:(NSDictionary *)dict;
26 -(instancetype)initWithDict:(NSDictionary *)dict;
27 @end
iOS开发多线程篇 11 —自定义NSOperation

YYappModel.m文件

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYappModel.m
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import "YYappModel.h"
10
11 @implementation YYappModel
12
13 -(instancetype)initWithDict:(NSDictionary *)dict
14 {
15 if (self=[super init]) {
16 [self setValuesForKeysWithDictionary:dict];
17 }
18 return self;
19 }
20
21 //工厂方法
22 +(instancetype)appModelWithDict:(NSDictionary *)dict
23 {
24 return [[self alloc]initWithDict:dict];
25 }
26 @end
iOS开发多线程篇 11 —自定义NSOperation

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

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYViewController.m
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import "YYViewController.h"
10 #import "YYappModel.h"
11
12 @interface YYViewController ()
13 @property(nonatomic,strong)NSArray *apps;
14
15 @end
16
17 @implementation YYViewController
18 #pragma mark- 懒加载
19 -(NSArray *)apps
20 {
21 if (_apps==nil) {
22 NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
23 NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
24
25 //字典转模型
26 NSMutableArray *array=[NSMutableArray array];
27 for (NSDictionary *dict in tempArray) {
28 YYappModel *app=[YYappModel appModelWithDict:dict];
29 [array addObject:app];
30 }
31 _apps=array;
32 }
33 return _apps;
34 }
35
36 #pragma mark-数据源方法
37 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
38 {
39 return self.apps.count;
40 }
41
42 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
43 {
44 static NSString *ID=@"ID";
45 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
46 if (cell==nil) {
47 cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
48 }
49 YYappModel *app=self.apps[indexPath.row];
50 cell.textLabel.text=app.name;
51 cell.detailTextLabel.text=app.download;
52
53 //下载图片数据
54 NSLog(@"加载图片数据---%@", [NSThread currentThread]);
55 NSURL *url=[NSURL URLWithString:app.icon];
56 NSData *data=[NSData dataWithContentsOfURL:url];
57 UIImage *imgae=[UIImage imageWithData:data];
58 cell.imageView.image=imgae;
59 NSLog(@"完成显示");
60 return cell;
61 }
62
63 @end
iOS开发多线程篇 11 —自定义NSOperation

打印查看:

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

二、自定义NSOperation

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

1.通过代理

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

YYdownLoadOperation.h文件

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYdownLoadOperation.h
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import <Foundation/Foundation.h>
10
11 #pragma mark-设置代理和代理方法
12 @class YYdownLoadOperation;
13 @protocol YYdownLoadOperationDelegate <NSObject>
14 -(void)downLoadOperation:(YYdownLoadOperation*)operation didFishedDownLoad:(UIImage *)image;
15 @end
16
17 @interface YYdownLoadOperation : NSOperation
18 @property(nonatomic,copy)NSString *url;
19 @property(nonatomic,strong)NSIndexPath *indexPath;
20 @property(nonatomic,strong)id <YYdownLoadOperationDelegate> delegate;
21 @end
iOS开发多线程篇 11 —自定义NSOperation

YYdownLoadOperation.m文件

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYdownLoadOperation.m
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import "YYdownLoadOperation.h"
10
11 @implementation YYdownLoadOperation
12 -(void)main
13 {
14 NSURL *url=[NSURL URLWithString:self.url];
15 NSData *data=[NSData dataWithContentsOfURL:url];
16 UIImage *imgae=[UIImage imageWithData:data];
17
18 NSLog(@"--%@--",[NSThread currentThread]);
19 //图片下载完毕后,通知代理
20 if ([self.delegate respondsToSelector:@selector(downLoadOperation:didFishedDownLoad:)]) {
21 dispatch_async(dispatch_get_main_queue(), ^{//回到主线程,传递数据给代理对象
22 [self.delegate downLoadOperation:self didFishedDownLoad:imgae];
23 });
24 }
25 }
26 @end
iOS开发多线程篇 11 —自定义NSOperation

主控制器中的业务逻辑:

iOS开发多线程篇 11 —自定义NSOperation
 1 //
2 // YYViewController.m
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import "YYViewController.h"
10 #import "YYappModel.h"
11 #import "YYdownLoadOperation.h"
12
13 @interface YYViewController ()<YYdownLoadOperationDelegate>
14 @property(nonatomic,strong)NSArray *apps;
15 @property(nonatomic,strong)NSOperationQueue *queue;
16
17 @end
18
19 @implementation YYViewController
20 #pragma mark- 懒加载apps
21 -(NSArray *)apps
22 {
23 if (_apps==nil) {
24 NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
25 NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
26
27 //字典转模型
28 NSMutableArray *array=[NSMutableArray array];
29 for (NSDictionary *dict in tempArray) {
30 YYappModel *app=[YYappModel appModelWithDict:dict];
31 [array addObject:app];
32 }
33 _apps=array;
34 }
35 return _apps;
36 }
37
38 #pragma mark-懒加载queue
39 -(NSOperationQueue *)queue
40 {
41 if (_queue==Nil) {
42 _queue=[[NSOperationQueue alloc]init];
43 //设置最大并发数为3
44 _queue.maxConcurrentOperationCount=3;
45 }
46 return _queue;
47 }
48
49 #pragma mark-数据源方法
50 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
51 {
52 return self.apps.count;
53 }
54 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
55 {
56 static NSString *ID=@"ID";
57 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
58 if (cell==nil) {
59 cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
60 }
61 YYappModel *app=self.apps[indexPath.row];
62 cell.textLabel.text=app.name;
63 cell.detailTextLabel.text=app.download;
64
65 //下载图片数据
66 // NSLog(@"加载图片数据---%@", [NSThread currentThread]);
67 // NSURL *url=[NSURL URLWithString:app.icon];
68 // NSData *data=[NSData dataWithContentsOfURL:url];
69 // UIImage *imgae=[UIImage imageWithData:data];
70 // cell.imageView.image=imgae;
71
72 //创建一个OPeration对象
73 YYdownLoadOperation *operation=[[YYdownLoadOperation alloc]init];
74 operation.url=app.icon;
75 operation.indexPath=indexPath;
76 operation.delegate=self;
77
78 //把操作对象添加到队列中在去
79 [self.queue addOperation:operation];
80
81 // NSLog(@"完成显示");
82 return cell;
83 }
84 -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
85 {
86 //返回图片数据给每行对应的cell的imageview.image
87 //取出tableview中indexPath这一行对应的cell
88 UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:operation.indexPath];
89 //显示图片
90 cell.imageView.image=image;
91 // NSLog(@"cell--index--%@---%@",operation.indexPath,[NSThread currentThread]);
92 //一定要刷新表格
93 [self.tableView reloadData];
94 NSLog(@"--%@--",[NSThread currentThread]);
95
96 }
97 @end
iOS开发多线程篇 11 —自定义NSOperation

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

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

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

问题3:保证一个url对应一个image。
下面对主控制器中得代码进行改进:
iOS开发多线程篇 11 —自定义NSOperation
  1 //
2 // YYViewController.m
3 // 01-自定义Operation
4 //
5 // Created by apple on 14-6-26.
6 // Copyright (c) 2014年 itcase. All rights reserved.
7 //
8
9 #import "YYViewController.h"
10 #import "YYappModel.h"
11 #import "YYdownLoadOperation.h"
12
13 @interface YYViewController ()<YYdownLoadOperationDelegate>
14 @property(nonatomic,strong)NSArray *apps;
15 @property(nonatomic,strong)NSOperationQueue *queue;
16 @property(nonatomic,strong)NSMutableDictionary *operations;
17 @property(nonatomic,strong)NSMutableDictionary *images;
18
19 @end
20
21 @implementation YYViewController
22 #pragma mark- 懒加载apps
23 -(NSArray *)apps
24 {
25 if (_apps==nil) {
26 NSString *path=[[NSBundle mainBundle]pathForResource:@"apps.plist" ofType:nil];
27 NSArray *tempArray=[NSArray arrayWithContentsOfFile:path];
28
29 //字典转模型
30 NSMutableArray *array=[NSMutableArray array];
31 for (NSDictionary *dict in tempArray) {
32 YYappModel *app=[YYappModel appModelWithDict:dict];
33 [array addObject:app];
34 }
35 _apps=array;
36 }
37 return _apps;
38 }
39
40 #pragma mark-懒加载queue
41 -(NSOperationQueue *)queue
42 {
43 if (_queue==Nil) {
44 _queue=[[NSOperationQueue alloc]init];
45 //设置最大并发数为3
46 _queue.maxConcurrentOperationCount=3;
47 }
48 return _queue;
49 }
50
51 #pragma mark-懒加载operations
52 -(NSMutableDictionary *)operations
53 {
54 if (_operations==Nil) {
55 _operations=[NSMutableDictionary dictionary];
56 }
57 return _operations;
58 }
59
60 #pragma mark-懒加载images
61 -(NSMutableDictionary *)images
62 {
63 if (_images==Nil) {
64 _images=[NSMutableDictionary dictionary];
65 }
66 return _images;
67 }
68
69 #pragma mark-数据源方法
70 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
71 {
72 return self.apps.count;
73 }
74 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
75 {
76 static NSString *ID=@"ID";
77 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:ID];
78 if (cell==nil) {
79 cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
80 }
81 YYappModel *app=self.apps[indexPath.row];
82 cell.textLabel.text=app.name;
83 cell.detailTextLabel.text=app.download;
84
85 //保证一个url对应一个image对象
86 UIImage *image=self.images[app.icon];
87 if (image) {//缓存中有图片
88 cell.imageView.image=image;
89 }else // 缓存中没有图片,得下载
90 {
91 //先设置一张占位图片
92 cell.imageView.image=[UIImage imageNamed:@"57437179_42489b0"];
93 YYdownLoadOperation *operation=self.operations[app.icon];
94 if (operation) {//正在下载
95 //什么都不做
96 }else //当前没有下载,那就创建操作
97 {
98 operation=[[YYdownLoadOperation alloc]init];
99 operation.url=app.icon;
100 operation.indexPath=indexPath;
101 operation.delegate=self;
102 [self.queue addOperation:operation];//异步下载
103 self.operations[app.icon]=operation;
104 }
105 }
106
107
108 return cell;
109 }
110 -(void)downLoadOperation:(YYdownLoadOperation *)operation didFishedDownLoad:(UIImage *)image
111 {
112 //1.移除执行完毕的操作
113 [self.operations removeObjectForKey:operation.url];
114
115 //2.将图片放到缓存中
116 self.images[operation.url]=image;
117
118 //3.刷新表格(只刷新下载的那一行)
119
120 [self.tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
121 NSLog(@"--%d--%@--",operation.indexPath.row,[NSThread currentThread]);
122
123 }
124 @end
iOS开发多线程篇 11 —自定义NSOperation

打印查看:

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

上一篇:Android Studio导入修改


下一篇:第三百零三节,Django框架介绍——用pycharm创建Django项目