Отмена NSOperationQueue из NSOperation - PullRequest
0 голосов
/ 04 июля 2010

У меня есть некоторый код iPhone SDK 4.0, который инициализирует NSOperationQueue, а затем добавляет три класса (ClassA, ClassB и ClassC) для запуска один за другим. ClassA, ClassB и ClassC являются подклассами NSOperation.

Соответствующий код указан ниже.

ClassA *classA = [[ClassA alloc] init];
ClassB *classB = [[ClassB alloc] init];
ClassC *classC = [[ClassC alloc] init];

[classB addDependency:classA];
[classC addDependency:classB];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperation:classA];
[queue addOperation:classB];
[queue addOperation:classC];

[classA release];
[classB release];
[classC release];
[queue release];

Причина зависимости заключается в том, что classB должен запускаться только в том случае, если classA успешно завершит свою работу. Аналогично, classC должен запускаться только в том случае, если classB завершается успешно.

В настоящий момент мне трудно понять, как, например, предотвратить запуск classB, если classA не завершится успешно. Продолжая этот пример, я думал о том, чтобы как-то вызвать [NSOperationQueue cancelAllOperations] из classA, но я не знаю, как получить указатель на родителя NSOperationQueue из classA (который является подпрограммой NSOperation). учебный класс). Это была только моя первоначальная мысль, поэтому я буду открыт для любых других лучших предложений для достижения того же результата!

В каждом из классов имеется условный код, позволяющий определить, правильно ли они завершились - на данный момент они просто отправляют NSLogging «Success» или «Fail» на консоль для целей отладки. В идеальном мире я просто хотел бы иметь возможность заменить оператор NSLog(@"Fail") в каждом классе некоторым кодом, который остановит запуск всех других классов в NSOperationQueue.

Любые предложения будут приветствоваться (и приветствуются).

Ответы [ 3 ]

3 голосов
/ 04 июля 2010

Вы можете установить свойство в классе A:

@property (readonly) BOOL completedSucessfully;

и установите это значение YES в конце основного метода класса A.

Тогда просто проверьте это в начале класса B.

- (void)main {
    if (NO == [[dependencies objectAtIndex:0] completedSucessfully])
        return;

Теперь classB просто остановится, если classA сообщит об ошибке.

NB. Вам, вероятно, потребуется дополнительная проверка ошибок, как в приведенном выше примере, т.е. проверка наличия зависимостей, проверка правильности класса и т. Д.

- (void)main {
    for (id *temp in [self dependencies])
        if ([temp isKindOfClass:[ClassA class]])
            if (NO == [(ClassA *)temp finishedSucessfully])
                return;
1 голос
/ 08 октября 2015

После просмотра сеанса WWDC 2015, посвященного передовым методам NSOperation (настоятельно рекомендуется), я начал использовать их в своем собственном коде.Вот несколько советов по достижению этого

  1. Из NSOperation вы можете вызвать [self currentQueue], чтобы получить «Очередь операций, запустивших операцию, или ноль, если очередь не может быть определена."Затем вы можете вызвать cancelAllOperations в возвращенной очереди.Опытным путем мне было трудно использовать этот подход, потому что, если вы явно выполняете код в основной очереди, имеете код в замыканиях / блоке или вызываете стороннюю библиотеку, то возвращенная очередь может вообще не быть исходной.В этой ситуации вызов метода cancelAllOperations не приведет к ожидаемому поведению - вместо этого вы отменяете операции в другой очереди.

  2. Подкласс NSOperation для включения свойства для начального NSOperationQueue и подкласса NSOperationQueue для установки свойства при добавлении операции в очередь.Затем вызовите cancelAllOperations для self.initialQueue.Этот подход я использую и работает во всех вышеупомянутых сценариях.

  3. Вместо отмены всех операций на уровне очереди вы можете вызвать метод «отмена» и завершить операцию.ваша операция.Если ваши операции написаны в соответствии с инструкциями Apple, все они проверяют isCancelled при запуске и прерывают обработку, если true.Это тонкое различие: когда вы отменяете операции с очередями, любые операции, которые не были начаты, вообще не будут запущены.Когда вы устанавливаете операции в isCancelled, последующие операции запускаются, но (должны) вскоре после этого заканчиваются.Это позволяет создавать сценарии, в которых более поздние операции могут выполнять некоторую очистку, обработку ошибок или уведомление пользователя.

1 голос
/ 20 марта 2011

Я бы предложил, если скорость не является проблемой, вы можете работать синхронно. Еще вы можете использовать:

[selector:@selctor(StartB) waitUntilTaskComplete:YES];
...