1

Например, у меня есть 3 объекта:NSOperationQueue: последовательность NSOperation с зависимостями VS (maxConcurrentOperationCount == 1)?

NSOperation *op1 = ...; 
NSOperation *op2 = ...; 
NSOperation *op3 = ...; 

[op3 addDependency:op2]; 
[op2 addDependency:op1]; 

NSOperationQueue *queue = ...; 
queue.maxConcurrentOperationCount = 1; 
[queue addOperations:@[op1, op2, op3] waitUntilFinished:NO]; 

Я мог бы просто добавить все операции в правильном порядке. Но, например, если op2 отменен, тогда я должен также отменить op3, и я не могу полностью очистить очередь в этом случае.

Мои вопросы:

1) Можно ли объединить такие последовательности операций с maxConcurrentOperationCount == 1?

2) Что будет делать программа, если я поменяю op1 и op2? (op2 должно выполняться после op1, но очередь может принимать только одну из операций одновременно)

P.S. В моей заявке я использую AFHTTPRequestOperation. Его иерархия наследования:

AFHTTPRequestOperation ->AFURLConnectionOperation ->NSOperation

Так что я не могу просто взять другой подкласс NSOperation.

ответ

1

Чтобы ответить на ваши вопросы:

  1. Это безопасно, чтобы объединить эту конкретную последовательность операций с зависимостями вы дали с maxConcurrentOperations = 1.
  2. Очередь будет работать op2, op3 и op1 или op2, op1, op3 если вы изменить порядок зависимостей op1 и op2.

Нет ничего сложного в цепочке зависимостей, которую вы указали, и NSOperationQueue может автоматически позаботиться о вещах. Вы можете действительно беспокоиться, если указали круговую зависимость (например, op3 зависит от op1), или у вас есть операция, которая не добавляется в очередь, и поэтому не может выполняться для удовлетворения зависимости.

Apple, это сказать об отмене в the NSOperationQueue class reference:

Отмена операции вызывает операцию игнорировать любые зависимости он может иметь. Такое поведение позволяет очереди как можно скорее выполнить метод запуска операции. Метод начала, в свою очередь, переводит операцию в законченное состояние, чтобы ее можно было удалить из очереди.

Все подклассы NSOperation должны корректно обрабатывать отмену, сначала проверяя, был ли он отменен, а затем немедленно завершили операцию без каких-либо действий. Если это не сделано, это ошибка, и операции могут выполняться, даже если они были отменены.

(Интересно, что это относится и к NSBlockOperation, чего я не понял. Вам явно нужно проверить self.isCancelled в блоке).

Я использовал CodeRunner в App Store, чтобы попробовать все это и немного изменил вашу программу. Он воспроизводится ниже.

#import <Foundation/Foundation.h> 

int main(int argc, char *argv[]) { 
    @autoreleasepool { 
     NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op1"); }]; 
     NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op2"); }]; 
     NSOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op3"); }]; 

     [op3 addDependency:op2]; 
     [op2 addDependency:op1]; 

     NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
     queue.maxConcurrentOperationCount = 1; 

     [queue addOperations:@[op1, op2, op3] waitUntilFinished:YES]; 
    } 
} 

Для NSBlockOperation, чтобы обратиться к себе, что нужно сделать это, что немного противно, но выглядит лучше в NSOperation подклассу, как вы можете обратиться к self.

__block NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op1 cancelled=%d", op1.cancelled); }]; 
+0

Я согласен с почти всем, но жду. 'NSBlockOperation' имеет' executeBlocks'. Должен ли я по-прежнему добавлять проверку на отмену, когда они являются отдельными блоками? – Gargo

+1

Очевидно, да, вам нужно явно проверить отмену операции даже в блоках. Вы можете попробовать это самостоятельно, отменив операцию, прежде чем добавить ее в очередь и посмотреть, что произойдет. –

+0

Если очередь, содержащая операцию блока, отменена, она даже не запускается. Вам нужно только проверить isCancelled, если вы делаете что-то медленное внутри блока, как цикл. – malhal