NSOperation
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
- (void)start;
一旦执行操作,就会调用target的sel方法
+ (id)blockOperationWithBlock:(void (^)(void))block;
- (void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
-------NSOperationQueue----
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
-------最大并发数----
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
-----队列的取消、暂停、恢复------
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
----操作优先级-----
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
[operationB addDependency:operationA]; // 操作B依赖于操作A
19.可以在不同queue的NSOperation之间创建依赖关系
20.注意:不能相互依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
// DYFViewController.m // 624-03-NSOperation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFViewController.h" @interface DYFViewController () @end @implementation DYFViewController - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [ self testOperationQueue]; } - ( void )testOperationListen { NSBlockOperation *operation3 = [ NSBlockOperation blockOperationWithBlock:^{ NSLog (@ "下载图片1111111%@" , [ NSThread currentThread]); // 下载图片 }]; operation3.completionBlock = ^{ // 下载完图片后想做的时期 }; // 2.创建队列 NSOperationQueue *queue = [[ NSOperationQueue alloc] init]; [queue addOperation:operation3]; } - ( void )testOperationQueue { // 1.封装操作 NSInvocationOperation *operation1 = [[ NSInvocationOperation alloc] initWithTarget: self selector: @selector (download) object: nil ]; NSInvocationOperation *operation2 = [[ NSInvocationOperation alloc] initWithTarget: self selector: @selector (run) object: nil ]; NSBlockOperation *operation3 = [ NSBlockOperation blockOperationWithBlock:^{ NSLog (@ "1111111%@" , [ NSThread currentThread]); }]; [operation3 addExecutionBlock:^{ NSLog (@ "222222%@" , [ NSThread currentThread]); }]; [operation3 addExecutionBlock:^{ NSLog (@ "33333%@" , [ NSThread currentThread]); }]; // 2.创建队列 NSOperationQueue *queue = [[ NSOperationQueue alloc] init]; // 5以内,2~3为宜 queue.maxConcurrentOperationCount = 2; #warning 面试题 // 设置操作依赖(一定要在添加到队列中前设置) [operation2 addDependency:operation1]; // 执行顺序取决于依赖,先执行完operation1再执行operation2 // 注意:不能相互依赖,循环操作 // 3.添加操作到队列中(自动执行操作,自动开启线程) [queue addOperation:operation1]; [queue addOperation:operation2]; [queue addOperation:operation3]; // 取消所有线程 //[queue cancelAllOperations]; // 暂停队列 //[queue setSuspended:YES]; // 设置操作优先级 //operation1.queuePriority = NSOperationQueuePriorityVeryHigh; } - ( void )testNSBlockOperation { // 1.创建操作对象,封装要执行的任务 NSBlockOperation *operation = [ NSBlockOperation blockOperationWithBlock:^{ for ( int i = 0; i < 11; i++) { NSLog (@ "1111111%@" , [ NSThread currentThread]); } }]; // 任务数在2各以上,就会开线程 [operation addExecutionBlock:^{ for ( int i = 0; i < 11; i++) { NSLog (@ "222222%@" , [ NSThread currentThread]); } }]; [operation addExecutionBlock:^{ for ( int i = 0; i < 11; i++) { NSLog (@ "33333%@" , [ NSThread currentThread]); } }]; // 2.执行操作 [operation start]; } - ( void )testNSInvocationOperation { // 1.创建操作对象,封装要执行的任务 NSInvocationOperation *operation = [[ NSInvocationOperation alloc] initWithTarget: self selector: @selector (download) object: nil ]; // 2.执行操作(默认情况下,若操作没有放到队列queue中,都是同步执行) [operation start]; } - ( void )download { for ( int i = 0; i < 11; i++) { NSLog (@ "download-----%@" , [ NSThread currentThread]); } } - ( void )run { for ( int i = 0; i < 11; i++) { NSLog (@ "run------%@" , [ NSThread currentThread]); } } @end |
----自定义NSOperation---
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// // DYFDownloadOperation.h // 624-05-自定义Operation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 dyf. All rights reserved. // #import <Foundation/Foundation.h> @class DYFDownloadOperation; @protocol DYFDownloadOperationDelegate < NSObject > @optional - ( void )downloadOperation:(DYFDownloadOperation *)operation didFinishedDownload:(UIImage *)image; @end @interface DYFDownloadOperation : NSOperation @property ( nonatomic , copy ) NSString *url; @property ( nonatomic , strong) NSIndexPath *indexPath; @property ( nonatomic , weak) id <DYFDownloadOperationDelegate> delegate; @end |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
// // DYFDownloadOperation.m // 624-05-自定义Operation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 dyf. All rights reserved. // #import "DYFDownloadOperation.h" @implementation DYFDownloadOperation /** * 在main方法中实现具体操作 */ - ( void )main { @autoreleasepool { if ( self .isCancelled) return ; NSURL *imaUrl = [ NSURL URLWithString: self .url]; if ( self .isCancelled) return ; // 下面这行很耗时 NSData *data = [ NSData dataWithContentsOfURL:imaUrl]; if ( self .isCancelled) return ; UIImage *image = [UIImage imageWithData:data]; if ( self .isCancelled) return ; // 返回主线程显示图片 // 通过代理 if ([ self .delegate respondsToSelector: @selector (downloadOperation:didFinishedDownload:)]) { [ self .delegate downloadOperation: self didFinishedDownload:image]; } } } @end |
具体利用MVC模式创建的文件老生常谈,只来一个Controller.m文件供参考,数据存储存在问题,可以改用SDWebImage框架处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
// // DYFTableViewController.m // 624-05-自定义Operation // // Created by dyf on 14-6-24. // Copyright (c) 2014年 ___FULLUSERNAME___. All rights reserved. // #import "DYFTableViewController.h" #import "DYFAppModel.h" #import "DYFDownloadOperation.h" #warning Dictionary基础知识不太理解,字典的赋值回去看看笔记 @interface DYFTableViewController ()<DYFDownloadOperationDelegate> @property ( nonatomic , strong) NSArray *apps; @property ( nonatomic , strong) NSOperationQueue *queue; /** * key:url value:operation对象 */ @property ( nonatomic , strong) NSMutableDictionary *oprations; /** * key:url value:image对象 */ @property ( nonatomic , strong) NSMutableDictionary *images; @end @implementation DYFTableViewController #pragma mark - 4个懒加载 - ( NSArray *)apps { if (!_apps) { NSString *path = [[ NSBundle mainBundle] pathForResource:@ "apps" ofType:@ "plist" ]; NSArray *arrayApps = [ NSArray arrayWithContentsOfFile:path]; NSMutableArray *arrayM = [ NSMutableArray arrayWithCapacity:arrayApps.count]; for ( NSDictionary *dict in arrayApps) { DYFAppModel *appM = [DYFAppModel appWithDict:dict]; [arrayM addObject:appM]; } _apps = arrayM; } return _apps; } - ( NSOperationQueue *)queue { if (!_queue) { _queue = [[ NSOperationQueue alloc] init]; // 设置最大并发线程数,最多同时下载3张图片 _queue.maxConcurrentOperationCount = 3; } return _queue; } - ( NSMutableDictionary *)oprations { if (!_oprations) { _oprations = [[ NSMutableDictionary alloc] init]; } return _oprations; } - ( NSMutableDictionary *)images { if (!_images) { _images = [ NSMutableDictionary dictionary]; } return _images; } - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } #pragma mark - 数据源方法 - ( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section { return self .apps.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath { // 1.创建cell static NSString *identifier = @ "apps" ; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]; } // 2.设置cell的数据 DYFAppModel *app = self .apps[indexPath.row]; cell.textLabel.text = app.name; cell.detailTextLabel.text = app.download; // 重点是如何从网络下载图片传入cell上面 // 每个url对应一个DYFDownloadOperation对象 // 每个url对应一个image对象 UIImage *image = self .images[app.icon]; if (image) { // 若缓存中存在图片 cell.imageView.image = image; } else { // 若缓存中不存在图片,则图片要从网上下载 // 设置下载前系统刷出的图片 cell.imageView.image = [UIImage imageNamed:@ "身份证小" ]; // 基础差,下面这行不太理解 DYFDownloadOperation *operation = self .oprations[app.icon]; if (operation) { // 若正在下载,则不执行其它操作 } else { // 若没在下载,则创建开始下载的子线程 DYFDownloadOperation *operation = [[DYFDownloadOperation alloc] init]; operation.url = app.icon; operation.indexPath = indexPath; operation.delegate = self ; // 添加任务进队列,异步下载 [ self .queue addOperation:operation]; // 基础差,下面这行不太理解 self .oprations[app.icon] = operation; } } // 3.返回cell return cell; } #pragma mark - DYFDownloadOperationDelegate - ( void )downloadOperation:(DYFDownloadOperation *)operation didFinishedDownload:(UIImage *)image { // 1.删除执行完毕的下载操作 [ self .oprations removeObjectForKey:operation.url]; // 若图片下载好 if (image) { // 2.将下载好的图片存入缓存 self .images[operation.url] = image; // 3.刷新这一行cell的数据 [ self .tableView reloadRowsAtIndexPaths:@[operation.indexPath] withRowAnimation:UITableViewRowAnimationNone]; // 4.将图片存入沙盒 // 4.1图片先转换为2进制数据 NSData *data = UIImagePNGRepresentation(image); // 4.2设置沙盒路径 NSString *path = [[ NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES ) lastObject] stringByAppendingPathComponent:[ self .apps[operation.indexPath.row] icon]]; NSLog (@ "%@" , path); // 4.3保存data到path中 [data writeToFile:path atomically: YES ]; } } // 开始拖拽时候暂停队列 - ( void )scrollViewWillBeginDragging:(UIScrollView *)scrollView { [ self .queue setSuspended: YES ]; } // 停止拖拽的时候重启队列 - ( void )scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { [ self .queue setSuspended: NO ]; } @end |