NSOperation和NSOperationQueue的理解和学习

来源:互联网 发布:vscode 设置文件类型 编辑:程序博客网 时间:2024/05/21 22:39

NSOperation本身是一个抽象的类,定义了一个要执行的工作。NSOperationQueue是一个工作队列,当NSOperation加入到队列时NSOperationQueue会按照优先级和从属依赖关系组织执行。

从头文件NSOperation.h来看接口是非常的简洁,NSOperation本身是一个抽象类,定义了一个要执行的工作,NSOperationQueue是一个工作队列,当工作加入到队列后,NSOperationQueue会自动按照优先顺序及工作的从属依赖关系(如果有的话)组织执行。

NSOperation是没法直接使用的,它只是提供了一个工作的基本逻辑,具体实现还是需要你通过定义自己的NSOperation子类来获得。如果有必要也可以不将NSOperation加入到一个NSOperationQueue中去执行,直接调用起-start也可以直接执行。

在继承NSOpertaion后,对于非并发的工作,只需要实现NSOperation子类的main方法:

1234567891011
-(void)main {   @try    {      // 处理工作任务   }   @catch(...)    {      // 处理异常,但是不能再重新抛出异常   }}

由于NSOperation的工作是可以取消Cancel的,那么你在main方法处理工作时就需要不断轮询[self isCancelled]确认当前的工作是否被取消了。

如果要支持并发工作,那么NSOperation子类需要至少override这四个方法:

  • start
  • isConcurrent
  • isExecuting
  • isFinished

实现了一个基于Operation的下载器,在Sample Code中可以下载。

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
- (void)operationDidStart{    [self.lock lock];    NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:self.URL                                                                cachePolicy:NSURLRequestReloadIgnoringCacheData                                                            timeoutInterval:self.timeoutInterval];    [request setHTTPMethod: @"GET"];    self.connection =[[NSURLConnection alloc] initWithRequest:request                                                     delegate:self                                             startImmediately:NO];    [self.connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];    [self.connection start];    [self.lock unlock];}- (void)operationDidFinish{    [self.lock lock];    [self willChangeValueForKey:@"isFinished"];    [self willChangeValueForKey:@"isExecuting"];    self.executing = NO;    self.finished = YES;    [self didChangeValueForKey:@"isExecuting"];    [self didChangeValueForKey:@"isFinished"];    [self.lock unlock];}- (void)start{    [self.lock lock];    if ([self isCancelled])    {        [self willChangeValueForKey:@"isFinished"];        self.finished = YES;        [self didChangeValueForKey:@"isFinished"];        return;    }    [self willChangeValueForKey:@"isExecuting"];    [self performSelector:@selector(operationDidStart) onThread:[[self class] networkThread] withObject:nil waitUntilDone:NO];    self.executing = YES;    [self didChangeValueForKey:@"isExecuting"];    [self.lock unlock];}- (void)cancel{    [self.lock lock];    [super cancel];    if (self.connection)    {        [self.connection cancel];        self.connection = nil;    }    [self.lock unlock];}- (BOOL)isConcurrent {    return YES;}- (BOOL)isExecuting {    return self.executing;}- (BOOL)isFinished {    return self.finished;}

start方法是工作的入口,通常是你用来设置线程或者其他执行工作任务需要的运行环境的,注意不要调用[super start];isConcurrent是标识这个Operation是否是并发执行的,这里曾经是个坑,如果你没有实现isConcurrent,默认是返回NO,那么你的NSOperation就不是并发执行而是串行执行的,不过在iOS5.0和OS X10.6之后,已经会默认忽略这个返回值,最终和Queue的maxConcurrentOperationCount最大并发操作值相关;isExecuting和isFinished是用来报告当前的工作执行状态情况的,注意必须是线程访问安全的。

注意你的实现要发出合适的KVO通知,因为如果你的NSOperation实现需要用到工作依赖从属特性,而你的实现里没有发出合适的“isFinished”KVO通知,依赖你的NSOperation就无法正常执行。NSOperation支持KVO的属性有:

  • isCancelled
  • isConcurrent
  • isExecuting
  • isFinished
  • isReady
  • dependencies
  • queuePriority
  • completionBlock

当然也不是说所有的KVO通知都需要自己去实现,例如通常你用不到addObserver到你工作的“isCancelled”属性,你只需要直接调用cancel方法就可以取消这个工作任务。

实现NSOperation子类后,可以直接调用start或者添加到一个NSOperationQueue里:

123
NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperation:downloader];


NSOperation和NSOperationQueue其他特性

工作是有优先级的,可以通过NSOperation的一下两个接口读取或者设置:

12
- (NSOperationQueuePriority)queuePriority;- (void)setQueuePriority:(NSOperationQueuePriority)p;

工作之间也可有从属依赖关系,只有依赖的工作完成后才会执行:

12
- (void)addDependency:(NSOperation *)op;- (void)removeDependency:(NSOperation *)op;

还可以通过下面接口设置运行NSOpration的子线程优先级:

1
- (void)setQueuePriority:(NSOperationQueuePriority)priority;

如果要设置Queue的并发操作数:

1
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

iOS4之后还可以往NSOperation上添加一个结束block,用于在工作执行结束之后的操作:

1
- (void)setCompletionBlock:(void (^)(void))block;

如果需要阻塞等待NSOperation工作结束(别在主线程这么干),可以使用接口:

1
- (void)waitUntilFinished;

NSOperationQueue除了添加NSOperation外,也支持直接添加一个Block(iOS4之后):

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

NSOperationQueue可以取消所有添加的工作:

1
- (void)cancelAllOperations;

也可以阻塞式的等待所有工作结束(别在主线程这么干):

1
- (void)waitUntilAllOperationsAreFinished;

在NSOperation对象中获得被添加的NSOperationQueue队列:

1
+ (id)currentQueue

要获得一个绑定在主线程的NSOperationQueue队列:

1
+ (id)mainQueue

NSInvocationOperation & NSBlockOperation

其实除非必要,简单的工作完全可以使用官方提供的NSOperation两个子类NSInvocationOperation和NSBlockOperation来实现。

NSInvocationOperation:

1234
NSInvocationOperation* theOp = [[NSInvocationOperation alloc]                        initWithTarget:self                                            selector:@selector(myTaskMethod:)                                                                          object:data];

NSBlockOperation:

1234
NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{      NSLog(@"Beginning operation.\n");      // Do some work.   }];

接口非常简单,一看便会。



0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 申诉找回微信密码验证吗错误怎么办 微信密码忘了申诉不成功怎么办 微信密码忘了申诉不了怎么办 微信密码忘了申诉不回来怎么办 微信号密码忘了申诉失败怎么办 手机微信密码忘了无需申诉怎么办 安全守护2手机绑定密码错误怎么办 新办的手机号注册过魅族账号怎么办 百度网盘手机找回被别人关了怎么办 把朋友微信号弄没了怎么办 小米顶配版手机无线网速度慢怎么办 刺激战场用过模拟器后用手机怎么办 百度网盘分享文件有违禁内容怎么办 百度网盘好友发的分享不存在怎么办 4g手机的下载速度很慢怎么办 为什么打开百度网盘的速度慢怎么办 百度网盘限制了我的宽带速度怎么办 联通信号很好但网速特别慢怎么办 苹果手机版本低下载不了软件怎么办 国内的手机要上推特和油管要怎么办 推特注册了卡在手机号怎么办 腾讯微信登录的账号密码忘了怎么办 打开手机浏览器自动跳到网页怎么办 游戏包解压后找不到启动的怎么办? 每次都要解压一次才能运行怎么办 误冲了王者荣耀点劵怎么办 机顶盒上开通的vip手机上怎么办 王者荣耀以前玩的区找不到了怎么办 电脑分辨率调高了游戏进不去怎么办 键盘语言更改后进不去系统怎么办 高尔夫旅行款 被锁在车内怎么办 在天猫买东西垫付的运费不退怎么办 天猫店一口价定价定低了怎么办 服务器开机账号改了密码忘了怎么办 小米儿童电话手表开不开机怎么办? 上海拍牌超过5次违章怎么办 拍拍贷不能更新还不了款怎么办 起诉网贷平台不知道地址怎么办 网贷不知道在哪个平台借的怎么办 车过户后出现问题车主不承认怎么办 卖了车买家一直不过户怎么办