Lmsgsendnilself

Uninhibited Soul, Free Craziness

NSOperation和NSOperationQueue的同步异步问题

| Comments

  前几天,同事问我NSOperation和NSOperationQueue的同步异步的事情,说看文档看的有点懵逼,于是研究了下文档细节,好好交流了这件事。缕了一下细节。

  1. NSOperation的start和main方法

       首先这俩方法都是调用执行NSOperation的,
      start: 这个方法手动执行NSOperation,需要注意的点:如果在子类化一个并发NSOperation,则必须override这个方法,并且用此方法初始化NSOperation; 这个方法禁止调用[super start];最后就是说这个方法要根据当前NSOperation的执行情况去做状态的切换,由于NSOperation是线程安全的,需要在不同状态的getter和setter方法里面加锁。并在状态的setter方法如setExecuting:setFinished:里面提供手动的KVO管理。
      main: 这个方法自动执行一个非并发的NSOperation。与start不同的是,如果在子类化一个并发NSOperation,main方法不是必须实现的,当然,如果想在start方法里面调用自己的main方法,也可以补充main方法,同样,main方法里面不要执行[super main]

  2. 使用NSOperationQueue方式自动管理NSOperations, NSOperations的 isConcurrent(现在为isAsynchronous)会被忽略,这是因为不管它为NO还是YES,NSOperationQueue都会提供一个独立的线程去执行,因此通过设置让它异步是没有意义的。

  3. 独立使用operations ,而不利用NSOperationQueue。 手动执行operation : operation为异步,不会阻塞当前线程;为同步则会阻塞 当前线程。

  4. waitUntilFinished使用问题

      当[operation waitUntilFinished]方法被调用后,将会等待直到operation结束。大概的顺序是    
    (1) operation 开始执行    
    (2) operation执行中    
    (3)当执行结束时,使用KVO方式通知所在NSOperationQueue。

      针对有无completion block,下面分别讨论。另外需要注意的是:completion blocks 要在异步operation中使用 ,在同步operation里面要避免使用。因此,下面谈论的completion blocks相关的前提都是基于异步operation的。
      1)如果我们没有用到completion block,使用waitUntilFinished的业务逻辑大概如下。

1
2
3
4
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:nil failure:nill];
[operation start];
[operation waitUntilFinished];
// parse operation.responseJSON and do other things

  2)如果用到了completion block ,需要特别注意的是,执行完上面的(1)(2)(3)步后,以下触发的几个事情不能保证执行顺序。    
(a) completion block 开始执行    
(b)waitUntilFinished 方法return    
(c)下一个operation开始执行
   由于以上执行循序的不确定性,通常情况下,我们就不能随便的将completion block在waitUntilFinished方法后执行来处理,除非做一些特定处理。 比如说项目里AFNetworking库版本升级之前,由于AFNetworking2.0里只提供了异步operation,为了实现同步效果,代码里使用dispatch_semaphore_t方法将的AFHTTPRequestOperation进行了同步处理。

1
2
3
4
5
6
7
8
9
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[_requestManager GET:@"resource" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
    // DO STH
      dispatch_semaphore_signal(semaphore);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    // DO STH
     dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

Comments