NSOperationQueue

博客介绍了NSOperationQueue的两种队列形式,主队列中的NSOperation在主线程执行,自定义队列的默认在子线程并发执行。还给出向队列添加操作的代码实例及源码,展示了添加单个和多个操作的方法,同时提到主线程会阻塞直到队列任务完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

001两种队列形式:主队列,自定义队列。添加到主队列的NSOperation会放在主线程中执行,放在自定义队列的NSOperation,默认放在子线程并发执行。

002 向NSOperationQueue添加操作

代码实例:

- (void)testAddFunction{
    
    NSOperationQueue *mainQueue = [NSOperationQueue currentQueue];
    
    NSOperationQueue  *theQueue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op1");
    }];
    
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op2");
    }];
    
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op3");
    }];
    
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op4");
    }];
    
    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op5");
    }];
    
    
    [mainQueue addOperation:op1];
    
    [mainQueue addOperations:@[op2,op4,op3,op5] waitUntilFinished:NO];
    
    [mainQueue  addOperationWithBlock:^{
        NSLog(@"addOperationWithBlock");
    }];
    
    
    
}

2020-11-01 10:30:59.576579+0800 GCDPropertyQueue[5216:477013] op1

2020-11-01 10:30:59.577015+0800 GCDPropertyQueue[5216:477013] op2

2020-11-01 10:30:59.579641+0800 GCDPropertyQueue[5216:477013] op4

2020-11-01 10:30:59.580128+0800 GCDPropertyQueue[5216:477013] op3

2020-11-01 10:30:59.580325+0800 GCDPropertyQueue[5216:477013] op5

2020-11-01 10:30:59.580565+0800 GCDPropertyQueue[5216:477013] addOperationWithBlock

 

003 如果NSOperationQueue添加了之前添加的操作那就会闪退

[mainQueue addOperation:op1];

 [mainQueue addOperation:op1];

[mainQueue addOperation:op1];

    [mainQueue addOperations:@[op2,op4,op3,op5,op1] waitUntilFinished:NO];

上源码:

- (void) addOperation: (NSOperation *)op

{

  if (op == nil || NO == [op isKindOfClass: [NSOperation class]])

    {

      [NSException raise: NSInvalidArgumentException

  format: @"[%@-%@] object is not an NSOperation",

NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

    }

  [internal->lock lock];

  if (NSNotFound == [internal->operations indexOfObjectIdenticalTo: op]

    && NO == [op isFinished])

    {

      [op addObserver: self

  forKeyPath: @"isReady"

      options: NSKeyValueObservingOptionNew

      context: isReadyCtxt];

      [self willChangeValueForKey: @"operations"];

      [self willChangeValueForKey: @"operationCount"];

      [internal->operations addObject: op];

      [self didChangeValueForKey: @"operationCount"];

      [self didChangeValueForKey: @"operations"];

      if (YES == [op isReady])

{

  [self observeValueForKeyPath: @"isReady"

      ofObject: op

change: nil

      context: isReadyCtxt];

}

    }

  [internal->lock unlock];

}

 

- (void) addOperations: (NSArray *)ops

     waitUntilFinished: (BOOL)shouldWait

{

  NSUInteger total;

  NSUInteger index;

 

  if (ops == nil || NO == [ops isKindOfClass: [NSArray class]])

    {

      [NSException raise: NSInvalidArgumentException

  format: @"[%@-%@] object is not an NSArray",

NSStringFromClass([self class]), NSStringFromSelector(_cmd)];

    }

  total = [ops count];

  if (total > 0)

    {

      BOOL invalidArg = NO;

      NSUInteger toAdd = total;

      GS_BEGINITEMBUF(buf, total, id)

 

      [ops getObjects: buf];

      for (index = 0; index < total; index++)

{

  NSOperation *op = buf[index];

 

  if (NO == [op isKindOfClass: [NSOperation class]])

    {

      invalidArg = YES;

      toAdd = 0;

      break;

    }

  if (YES == [op isFinished])

    {

      buf[index] = nil;

      toAdd--;

    }

}

      if (toAdd > 0)

{

          [internal->lock lock];

  [self willChangeValueForKey: @"operationCount"];

  [self willChangeValueForKey: @"operations"];

  for (index = 0; index < total; index++)

    {

      NSOperation *op = buf[index];

 

      if (op == nil)

{

  continue; // Not added

}

      if (NSNotFound

!= [internal->operations indexOfObjectIdenticalTo: op])

{

  buf[index] = nil; // Not added

  toAdd--;

  continue;

}

      [op addObserver: self

  forKeyPath: @"isReady"

      options: NSKeyValueObservingOptionNew

      context: isReadyCtxt];

      [internal->operations addObject: op];

      if (NO == [op isReady])

{

  buf[index] = nil; // Not yet ready

}

    }

  [self didChangeValueForKey: @"operationCount"];

  [self didChangeValueForKey: @"operations"];

  for (index = 0; index < total; index++)

    {

      NSOperation *op = buf[index];

 

      if (op != nil)

{

  [self observeValueForKeyPath: @"isReady"

      ofObject: op

change: nil

      context: isReadyCtxt];

}

    }

          [internal->lock unlock];

}

      GS_ENDITEMBUF()

      if (YES == invalidArg)

{

  [NSException raise: NSInvalidArgumentException

    format: @"[%@-%@] object at index %"PRIuPTR" is not an NSOperation",

    NSStringFromClass([self class]), NSStringFromSelector(_cmd),

    index];

}

    }

  if (YES == shouldWait)

    {

      [self waitUntilAllOperationsAreFinished];

    }

}

 

    NSOperationQueue *mainQueue = [NSOperationQueue currentQueue];

    [mainQueue addOperations:@[op2,op4,op3,op5] waitUntilFinished:YES]; 

主线程将会阻塞,直到队列中的所有任务完成。

- (void) waitUntilAllOperationsAreFinished

{

  NSOperation *op;

 

  [internal->lock lock];

  while ((op = [internal->operations lastObject]) != nil)

    {

      [op retain];

      [internal->lock unlock];

      [op waitUntilFinished];

      [op release];

      [internal->lock lock];

    }

  [internal->lock unlock];

}

 

对比 GCD 与 NSOperationQueue

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值