Как остановить NSInvocationOperation?

У меня есть NSInvocationOperation, которая будет загружать и анализировать серию NSXMLDocuments в фоновом режиме, реагируя на мой пользовательский интерфейс.

Моя попытка остановить операцию Invocation состоит в том, чтобы вызвать метод cancellAllOperations моего NSOperationQueue. Но похоже, что это не остановит выполнение вызова.

Любые идеи о том, как я могу решить эту проблему?


person Earl Claridad    schedule 18.04.2009    source источник


Ответы (4)


Реализация вашего объекта NSOperation должна фактически остановить то, что он делает, очистить и выйти, когда он получит уведомление об отмене. Сообщение о том, что вы хотите отменить все операции в очереди, приведет к тому, что очередь перестанет исключать из очереди новые операции для выполнения и отправит сообщение об отмене всем выполняемым в данный момент операциям.

В основном методе вашей операции вы должны проверять isCancelled и обрабатывать это состояние, когда вы фактически отменяетесь.

Для получения дополнительной информации см. Создание и управление объектами операций в Руководстве по программированию потоков.

person Jason Coco    schedule 18.04.2009
comment
Но посмотрите другие ответы, похоже, вы не можете этого сделать (по крайней мере, стандартным способом проверки isCancelled) при использовании NSInvocationOperation. - person jrdioko; 31.05.2011

ОБНОВЛЕНИЕ: Когда я делаю это, инструменты показывают много утечек. Действовать осторожно! Я держу это здесь на случай, если я действительно что-то найду, и кто-то еще сможет понять, как преодолеть препятствие утечки.

Вот извращенная идея, которую я повторяю, когда печатаю это:

Установите операцию как объект для метода initWithTarget:selector:object: NSInvocationOperation. Предположим, что у вас уже есть NSOperationQueue (назовем ее queue):

NSInvocationOperation *operation = [NSInvocationOperation alloc];
operation = [operation initWithTarget:self selector:@selector(myOperation:) object:operation];
[queue addOperation:operation];
[operation release];

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

Затем в методе операции верните объект обратно и добавьте проверки для isCancelled по желанию. Например:

  - (void)myOperation:(id)object {
    NSInvocationOperation *operation = (NSInvocationOperation *)object;
    if ([operation isCancelled]) return;
    ...
  }

Убедитесь, что ваш селектор заканчивается двоеточием в вызове initWithTarget:..., так как теперь вы будете передавать объект.

Все идет нормально. Теперь, если я смогу принудительно выполнить cancelAllOperations, я узнаю, действительно ли это работает. :)

person Joe D'Andrea    schedule 11.08.2009
comment
Не буду пробовать из-за протечек. Но идея отличная! - person Mike Keskinov; 13.06.2012

Вам нужно проверить, если NSInvocationOperation isCancelled имеет значение YES. Для этого в NSInvocationOperation вы можете использовать Key Value Observation:

Добавьте свой объект в качестве наблюдателя NSInvocationOperation isCancelled при выполнении операции:

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:<targetObj> selector:@selector(<targetMethod>) object:nil];
[operation addObserver:<targetObj> forKeyPath:@"isCancelled" options:NSKeyValueObservingOptionNew context:nil];
[operQueue addOperation:operation];
[operation release];

Затем в targetObj реализовать

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;

следить за изменением isCancelled с помощью метода NSOperationQueue cancellAllOperations. Здесь вы можете установить частный флаг, и targetMethod сможет проверить его и отменить при необходимости.

person komorian    schedule 02.06.2010

Пост выше отличный, но для более прямого ответа на исходный вопрос: похоже, вы не можете остановить объект NSInvocationOperation, потому что он не поддерживает отмену. Вам придется создать подкласс.

person EightyEight    schedule 01.05.2009