NSOperation

 
http://www.cnblogs.com/dyf520/p/3805297.html
 
 
-------NSOperation简介----
1.NSOperation的作用
·配合使用NSOperation和NSOperationQueue也能实现多线程编程
 
2.NSOperation和NSOperationQueue实现多线程的具体步骤
·先将需要执行的操作封装到一个NSOperation对象中
·然后将NSOperation对象添加到NSOperationQueue中
·系统会自动将NSOperation中封装的操作放到一条新线程中执行
 
---------NSOperation的子类----
3.NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
 
4.使用NSOperation子类的方式有3种
·NSInvocationOperation
·NSBlockOperation
·自定义子类继承NSOperation,实现内部相应的方法
 
------NSInvocationOperation---
5.创建NSInvocationOperation对象

- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

6.调用start方法开始执行操作

- (void)start;

一旦执行操作,就会调用target的sel方法

7.注意
·默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
·只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
 
 
-------NSBlockOperation--
8.创建NSBlockOperation对象

+ (id)blockOperationWithBlock:(void (^)(void))block;

9.通过addExecutionBlock:方法添加更多的操作

- (void)addExecutionBlock:(void (^)(void))block;

注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作

-------NSOperationQueue----

10.NSOperationQueue的作用
·NSOperation可以调用start方法来执行任务,但默认是同步执行的
·如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
 
11.添加操作到NSOperationQueue中

- (void)addOperation:(NSOperation *)op;

- (void)addOperationWithBlock:(void (^)(void))block;

-------最大并发数----

12.什么是并发数
·同时执行的任务数
·比如,同时开3个线程执行3个任务,并发数就是3
 
13.最大并发数的相关方法

- (NSInteger)maxConcurrentOperationCount;

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

-----队列的取消、暂停、恢复------

14.取消队列的所有操作

- (void)cancelAllOperations;

提示:也可以调用NSOperation的- (void)cancel方法取消单个操作

15.暂停和恢复队列

- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列

- (BOOL)isSuspended;

----操作优先级-----

16.设置NSOperation在queue中的优先级,可以改变操作的执行顺序

- (NSOperationQueuePriority)queuePriority;

- (void)setQueuePriority:(NSOperationQueuePriority)p;

17.优先级的取值(优先级越高,越先执行)
·NSOperationQueuePriorityVeryLow = -8L,
·NSOperationQueuePriorityLow = -4L,
·NSOperationQueuePriorityNormal = 0,
·NSOperationQueuePriorityHigh = 4,
·NSOperationQueuePriorityVeryHigh = 8
 
---操作依赖---
18.NSOperation之间可以设置依赖来保证执行顺序
·比如一定要让操作A执行完后,才能执行操作B,可以这么写

[operationB addDependency:operationA]; // 操作B依赖于操作A

19.可以在不同queue的NSOperation之间创建依赖关系

20.注意:不能相互依赖

·比如A依赖B,B依赖A
----操作的执行顺序---
21.对于添加到queue中的operations,它们的执行顺序取决于2点
·首先依据NSOperation之间的依赖关系
·然后依据NSOperation的优先级
 
22.因此,总体的执行顺序是
·先满足依赖关系
·然后再从NSOperation中选择优先级最高的那个执行
 
 
 
---自定义NSOperation---
23.自定义NSOperation的步骤很简单
·重写- (void)main方法,在里面实现想执行的任务
 
24.重写- (void)main方法的注意点
·自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
·经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
 
 
 
--------分割线---
NSOperation小代码1,
只写一个文件参考下
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
 
 
 
原文地址:https://www.cnblogs.com/Cheetah-yang/p/4664010.html