多线程NSOperation--自定义非并行的 NSOperation(二)
来源:互联网 发布:淘宝个性化标签 算法 编辑:程序博客网 时间:2024/05/21 21:41
转自:http://www.jianshu.com/p/813f7d58935d
1 自定义非并行的 NSOperation
前文介绍过 NSInvocationOperation 和 NSBlockOperation 都继承自NSOperation类。
我们亦可以通过继承 NSOperation 类,来自定义非并行的 Operation。
@interface VinnyOperation : NSOperation@end
头文件很简单,只需要继承 NSOperation ,可根据实际需要决定是否需要自定义init
方法。而且仅仅需要自定义main
方法,将需要执行的操作写在main
方法中。
#import "VinnyOperation.h"@implementation VinnyOperation- (void)main{ NSLog(@"main begin"); @try { // 提供一个变量标识,来表示需要执行的操作是否完成了,当然,没开始执行之前,为NO BOOL taskIsFinished = NO; // while 保证:只有当没有执行完成和没有被取消,才执行自定义的相应操作 while (taskIsFinished == NO && [self isCancelled] == NO){ // 自定义的操作 sleep(10); // 睡眠模拟耗时操作 NSLog(@"currentThread = %@", [NSThread currentThread]); NSLog(@"mainThread = %@", [NSThread mainThread]); // 这里相应的操作都已经完成,后面就是要通知KVO我们的操作完成了。 taskIsFinished = YES; } } @catch (NSException * e) { NSLog(@"Exception %@", e); } NSLog(@"main end");}@end
使用的时候也非常简单
VinnyOperation *op = [[VinnyOperation alloc] init]; NSLog(@"start before"); [op start]; NSLog(@"start after");
看一下控制台打印的结果
2015-12-29 19:21:56.895 test[67010:50712745] start before2015-12-29 19:21:56.896 test[67010:50712745] main begin2015-12-29 19:22:06.900 test[67010:50712745] currentThread = <NSThread: 0x7fc560d044d0>{number = 1, name = main}2015-12-29 19:22:06.900 test[67010:50712745] mainThread = <NSThread: 0x7fc560d044d0>{number = 1, name = main}2015-12-29 19:22:06.900 test[67010:50712745] main end2015-12-29 19:22:06.900 test[67010:50712745] start after
可以看出是main
方法是非并行的,而且执行的操作与调用start
是在同一个线程中。
2 自定义并行的 NSOperation
自定义并行的 NSOperation 则要复杂一点,首先必须重写以下几个方法:
start
: 所有并行的 Operations 都必须重写这个方法,然后在你想要执行的线程中手动调用这个方法。注意:任何时候都不能调用父类的start
方法。main
: 在start
方法中调用,但是注意要定义独立的自动释放池与别的线程区分开。isExecuting
: 是否执行中,需要实现KVO通知机制。isFinished
: 是否已完成,需要实现KVO通知机制。isConcurrent
: 该方法现在已经由isAsynchronous
方法代替,并且 NSOperationQueue 也已经忽略这个方法的值。isAsynchronous
: 该方法默认返回 NO ,表示非并发执行。并发执行需要自定义并且返回 YES。后面会根据这个返回值来决定是否并发。
与非并发操作不同的是,需要另外自定义一个方法来执行操作而不是直接调用start
方法
@interface MyOperation : NSOperation- (BOOL)performOperation:(NSOperation*)anOp; // 执行操作调用这个方法@end
实现其中的必要方法:
#import "MyOperation.h"@interface MyOperation () { BOOL executing; // 执行中 BOOL finished; // 已完成}@end@implementation MyOperation- (id)init { self = [super init]; if (self) { executing = NO; finished = NO; } return self;}- (void)start { // Always check for cancellation before launching the task. if ([self isCancelled]) { // Must move the operation to the finished state if it is canceled. [self willChangeValueForKey:@"isFinished"]; finished = YES; [self didChangeValueForKey:@"isFinished"]; return; } // If the operation is not canceled, begin executing the task. [self willChangeValueForKey:@"isExecuting"]; [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil]; executing = YES; [self didChangeValueForKey:@"isExecuting"];}- (void)main { NSLog(@"main begin"); @try { // 必须为自定义的 operation 提供 autorelease pool,因为 operation 完成后需要销毁。 @autoreleasepool { // 提供一个变量标识,来表示需要执行的操作是否完成了,当然,没开始执行之前,为NO BOOL taskIsFinished = NO; // while 保证:只有当没有执行完成和没有被取消,才执行自定义的相应操作 while (taskIsFinished == NO && [self isCancelled] == NO){ // 自定义的操作 //sleep(10); // 睡眠模拟耗时操作 NSLog(@"currentThread = %@", [NSThread currentThread]); NSLog(@"mainThread = %@", [NSThread mainThread]); // 这里相应的操作都已经完成,后面就是要通知KVO我们的操作完成了。 taskIsFinished = YES; } [self completeOperation]; } } @catch (NSException * e) { NSLog(@"Exception %@", e); } NSLog(@"main end");}- (void)completeOperation { [self willChangeValueForKey:@"isFinished"]; [self willChangeValueForKey:@"isExecuting"]; executing = NO; finished = YES; [self didChangeValueForKey:@"isExecuting"]; [self didChangeValueForKey:@"isFinished"];}// 已经弃用,使用 isAsynchronous 代替//- (BOOL)isConcurrent {// return NO;//}- (BOOL)isAsynchronous { return YES;}- (BOOL)isExecuting { return executing;}- (BOOL)isFinished { return finished;}// 执行操作- (BOOL)performOperation:(NSOperation*)anOp{ BOOL ranIt = NO; if ([anOp isReady] && ![anOp isCancelled]) { if (![anOp isAsynchronous]) { [anOp start]; } else { [NSThread detachNewThreadSelector:@selector(start) toTarget:anOp withObject:nil]; } ranIt = YES; } else if ([anOp isCancelled]) { // If it was canceled before it was started, // move the operation to the finished state. [self willChangeValueForKey:@"isFinished"]; [self willChangeValueForKey:@"isExecuting"]; executing = NO; finished = YES; [self didChangeValueForKey:@"isExecuting"]; [self didChangeValueForKey:@"isFinished"]; // Set ranIt to YES to prevent the operation from // being passed to this method again in the future. ranIt = YES; } return ranIt;}
使用这个 Operation 如下:
MyOperation *op = [[MyOperation alloc] init]; NSLog(@"start before"); [op performOperation:op]; NSLog(@"start after");
看一下控制台打印的结果
2015-12-29 20:01:53.130 test[27083:51105353] start before2015-12-29 20:01:53.131 test[27083:51105353] start after2015-12-29 20:01:53.131 test[27083:51105608] main begin2015-12-29 20:01:53.131 test[27083:51105608] currentThread = <NSThread: 0x7ff148d976d0>{number = 3, name = (null)}2015-12-29 20:01:53.131 test[27083:51105608] mainThread = <NSThread: 0x7ff148e01250>{number = 1, name = (null)}2015-12-29 20:01:53.131 test[27083:51105608] main end
可以看到这个操作是并发执行,并且是一个独立的线程。
3 总结
- 如果需要自定义并发执行的 Operation,必须重写
start
、main
、isExecuting
、isFinished
、isAsynchronous
方法。 - 在 operation 的 main 方法里面,必须提供 autorelease pool,因为你的 operation 完成后需要销毁。
- 一旦你的 operation 开始了,必须通过 KVO,告诉所有的监听者,现在该operation的执行状态。
- 调用时,如果需要并发执行 Operation,必须调用
performOperation:
方法,当然,也可以改为自定义其他方法或者直接在start
方法添加多线程调用。 - 对于自定义的 Operation 类,如果不需要并发执行,可以直接调用
start
方法。
4 尾巴
刚开始看 NSOperation 的文档没搞明白怎么自定义多线程的操作,文档里只是说需要自定义 isExecuting
、isFinished
、isConcurrent
、isAsynchronous
这四个方法,然后说根据 isAsynchronous
的返回值来判断是否多线程,我以为只要重写这个方法的时候返回 YES 就行了,NSOperation 就会自动多线程执行了,但是测试发现却不是这样的,多线程还得自己去创建再使用。
再有就是自定义多线程的 NSOperation 时,还必须自己管理其中表示状态的成员,而且需要实现 KVO 机制,使得这个过程复杂化了。
其实在大多数时候我们并不会直接去使用自定义的 NSOperation ,如果操作不复杂,可以直接使用 NSInvocationOperation 和 NSBlockOperation 这两个子类,那就直接用了,如果复杂一些,必须自定义又需要多线程,通常都会用 NSOperationQueue 来包装,使用起来更加简洁,下一篇会详细介绍 NSOperationQueue 的使用。
- 多线程NSOperation--自定义非并行的 NSOperation(二)
- iOS多线程 (二)-----------NSOperation
- 自定义NSOperation(二)
- NSOperation多线程的使用
- iOS开发多线程-自定义NSOperation
- 《多线程——自定义NSOperation》
- iOS多线程之二 NSOperation
- 多线程的使用(3) - NSOperation的并发与非并发
- 多线程的使用(3) - NSOperation的并发与非并发
- 多线程的使用(3) - NSOperation的并发与非并发
- 多线程 NSOperation
- NSOperation多线程
- 多线程:NSOperation
- 多线程-NSOperation
- 多线程 NSOperation
- 多线程-NSOperation
- 自定义NSOperation
- 自定义 NSOperation
- AFL(American Fuzzy Lop)使用(一)
- linux grep
- sparkSQL元数据缓存踩的坑
- 微信小程序从入门到放弃(五)
- xtu 1266 Parentheses 2017湘潭邀请赛G
- 多线程NSOperation--自定义非并行的 NSOperation(二)
- SpringMVC用ajax到前台乱码解决办法
- vxWorks内核解读六--初始化
- Java常用的八种排序算法与代码实现
- java中getter和setter方法的理解
- MFC控件大小随窗体大小而改变
- 卷积神经网络
- java中的单例设计模式
- Quartz 时间设置