做一下整理,与大家分享,不足之处请留言:
使用NSOperation时,需要使用其子类:子类有三种方式
1.NSInvocationOperation 2.NSBlockOperation 3.自定义子类继承NSOperation,实现内部相应的方法
NSInvocationOperation 2个初始化方法
- (id)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg;
- (void)start;//执行操作
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:nil];
[operation start];
注意:默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作。只有将operation放到一个NSOperationQueue中,才会异步执行操作。
NSBlockOperation
创建NSBlockOperation对象 + (id)blockOperationWithBlock:(void (^)(void))block;
通过addExecutionBlock:方法添加更多的操作 - (void)addExecutionBlock:(void (^)(void))block;
用法:
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行了一个同步操作");
}];
[operation addExecutionBlock:^() { //异步操作
NSLog(@"执行了第2个新的操作,线程:%@", [NSThread currentThread]); }];
[operation addExecutionBlock:^() { //异步操作
NSLog(@"执行了第3个新的操作,线程:%@", [NSThread currentThread]); }];
[operation start];// 开始执行任务
注意:一般情况下,如果一个NSBlockOperation对象封装了多个任务。那么除第一个任务外,其他的任务会在新线程(子线程)中执行。即,NSBlockOperation是否开启新线程取决于任务的个数,任务的个数多,会自动开启新线程。但是第一个被执行的任务是同步执行,除第一个任务外,其他任务是异步执行的。
NSOperationQueue
NSOperation可以调用start方法来执行任务,但默认是同步执行的,如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
NSOperation的completionBlock属性
如果想在操作执行完毕之后,还希望做一些其他的事情,可以通过completionBlock实现,并且永远是等待操作所有任务执行完毕最后被调用。
同步执行
NSBlockOperation *blkop = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:3];
NSLog(@"执行%@",[NSThread currentThread]); }];
blkop.completionBlock = ^{ NSLog(@"完成"); };
[blkop start];
异步执行
NSBlockOperation *blkop = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:4];
NSLog(@"执行%@",[NSThread currentThread]); }];
blkop.completionBlock = ^{ NSLog(@"完成"); };
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:blkop];
//如果一个操作是被加到操作队列中,然后才设置completionBlock,这样是可以的
总结:如果操作是通过调用start方法触发的,那么completionBlock必须要在start之前设置。如果操作是通过加入操作队列被触发的,那么completionBlock可以在操作添加到操作队列之后设置,只要保证此时操作没有被执行即可。
最大并发数 同时执行的任务数
最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 设置最大并发操作数 // queue.maxConcurrentOperationCount = 5;
queue.maxConcurrentOperationCount = 1; // 就变成了串行队列
NSOperation添加Dependency
操作B依赖于操作A,所以一定要等操作A执行完毕才能执行操作B。执行顺序,不取决于添加到队列的先后顺序,而是取决于依赖关系(注:maxConcurrentOperationCount = 1除外,因为maxConcurrentOperationCount = 1时,操作队列为串行队列,如果没有给操作添加依赖,此时操作的执行顺序取决于操作添加到队列中的先后顺序。即便如此,maxConcurrentOperationCount = 1时,队列中的操作也并不一定在同一个线程中执行)
[operationB addDependency:operationA]; // 操作B依赖于操作A
如果操作设置了依赖,也给队列设置了maxConcurrentOperationCount = 1。那么操作被执行的顺序取决于依赖。即,依赖的优先级较高。
NSBlockOperation *blkop1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"执行1 %@",[NSThread currentThread]); }];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSBlockOperation *blkop2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"执行2 %@",[NSThread currentThread]); }];
[blkop1 addDependency:blkop2];//blkop1依赖于blkop2
[queue addOperation:blkop1];
[queue addOperation:blkop2];
注意:一定要在操作添加到队列之前设置操作之间的依赖,否则操作已经添加到队列中在设置依赖,依赖不会生效。依赖关系不局限于相同queue中的NSOperation对象,NSOperation对象会管理自己的依赖, 因此不同的操作队列之间的操作也可以设置依赖
队列的取消、暂停、恢复
取消队列的所有操作
- (void)cancelAllOperations;//取消所有操作
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;