Композитный NSOperation.Это плохая идея? - PullRequest
3 голосов
/ 20 января 2011

Для приложения iOS4.X, над которым я работаю, нам часто нужно выполнить HTTP-запрос, затем проанализировать результаты и что-то сделать с результатами, и т. Д.

Для этого я создалКласс NSOperation, чтобы позволить составление NSOperations, используя очередь NSOperation.Есть ли проблемы с использованием NSOperationQueues для небольших вещей, как это.Некоторые говорят мне, что очереди должны быть более постоянными.

Я не ожидаю, что в нашем приложении вложенность будет более чем на 2 уровня.

Вот пример такого использования:

@implementation CompositeOperation

- (id)initWithOperations:(NSArray *)operations {
    if ((self = [super init])) {
        operations_ = [operations retain];
        [[operations_ lastObject] addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:nil];

    }
    return self;
}

-(void)dealloc {
    [operations_ release];
    [operationQueue_ release];
    [super dealloc];
}

- (BOOL)isConcurrent {
    return YES;
}

@synthesize isExecuting = isExecuting_;
@synthesize isFinished = isFinished_;
@synthesize operations = operations_;

- (void) start {
    if (![self isCancelled]) {
        operationQueue_ = [[NSOperationQueue alloc] init];
        // TODO: Add code to execute this serially
        [operationQueue_ addOperations:operations_ waitUntilFinished:NO];
    }
}

- (void)cancel {
    if (operationQueue_) {
        [operationQueue_ cancelAllOperations];
    }
    [super cancel];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqualToString:@"isFinished"] && object == [operations_ lastObject]) {
        [self setIsFinished:YES];
    }
}

@end

Спасибо, Майк

1 Ответ

2 голосов
/ 05 октября 2015

Я тот, кто считает, что это очень хорошая идея, поэтому я даже создал библиотеку после нее: CompositeOperations .

Существует две операции: простая операция, представленная COSimpleOperation объектом, и составная операция, представленная COCompositeOperation объектом.

Простая операция - наименьшая возможная единица - процитировать документацию:

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

Составная операция - это операция, которая состоит из подопераций. Процитирую @mikelikespie:

Цель этого объекта - сделать так, чтобы можно было представлять несколько операций, которые логически сгруппированы как одна операция.

... это еще одно описание Composite Design Pattern от Gang of Four Design Patterns.

Составная операция может быть parallel или sequential.

Параллельные операции создаются так же, как в рассматриваемом примере кода:

NSArray *operations = @[ 
    operation1, operation2, operation3 
]; // each operation is NSOperation <COOperation> *

COCompositeOperation *parallelOperation = [[COCompositeOperation alloc] initWithOperations:operations];

Для создания последовательной операции необходимо создать экземпляр COCompositeOperation с объектом, соответствующим протоколу COSequence:

Последовательная композиция подразумевает последовательный поток: подоперации выполняются последовательно одна за другой. Секвенирование достигается за счет сотрудничества между COCompositeOperation и произвольным классом, соответствующим протоколу COSequence, который используется составной операцией в качестве делегата, который решает, какие операции и в каком порядке их запускать.

Чтобы сделать эту композицию операций возможной, мне нужно было наложить небольшое ограничение на работу библиотеки операций с: помимо того, что NSOperations, COSimpleOperation и COCompositeOperation также соответствуют протоколу <COOperation>:

Это соответствие в основном означает, что обе операции после завершения имеют 3 возможных состояния:

  1. непустое поле результата указывает на успех

  2. непустое поле ошибки указывает на сбой

  3. как пустые поля результатов, так и поля ошибок указывают, что операция была отменена извне (с использованием метода [NSOperation cancel]).

Операция никогда не может содержать поля результата и ошибки не пустыми!

Это соглашение позволяет составным операциям решать в определенный момент, продолжать ли выполнение определенной группы операций или остановить ее. Для операций без определенного результата [NSNull null] должен быть передан как результат.


Для меня рациональной основой этой библиотеки было «просто» представлять операции так, чтобы «они логически сгруппировались как одна операция». Существуют библиотеки, которые достигают такого же рода функциональности более высокого уровня, но в то же время они вводят такие понятия, как: Сигналы в ReactiveCocoa или Обещания, как в PromiseKit , которые я не очень нужно или я бы сказал не согласен с. Я хотел что-то как можно более простое и основанное на старой доброй хорошо известной инфраструктуре NSOperation / NSOperationQueue, так что в этом смысл всей работы.

P.S. Я надеюсь, что такой ответ подходит SO, по крайней мере, он точно соответствует тому, что @mikelikespie спрашивал около 4 лет назад.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...