как отменить работу, созданную с помощью addOperationWithBlock?

Я использую addOperationWithBlock NSOperationQueue. Изнутри блока, как я могу проверить, должен ли я отменить операцию? Или получить доступ к любым свойствам/методам NSOperation?

[myOperationQueue addOperationWithBlock: ^{

  while ( /* long running loop */ )
  {
      // how to determine here if I need to cancel?
      // for that matter, access any NSOperation properties/methods?

  }

}];

Является ли лучший способ сделать это с помощью NSBlockOperation?


person TomSwift    schedule 10.02.2011    source источник


Ответы (2)


Лучшим решением может быть использование NSBlockOperation и добавление его в очередь вместо необработанного блока. Вы можете сделать что-то вроде:

__block NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
  while(![operation isCancelled]){
    //Some long operation
  }
}];

[[self queue] addOperation:operation];

Это позволяет вам использовать блоки, давая вам немного больше контроля над операцией... и еще несколько NSOperation тонкостей (например, возможность добавлять блоки завершения).

person jemmons    schedule 13.11.2011
comment
это почти то, что я хочу. но это работает только в этом конкретном блоке. в моем случае мой блок вызывает другую функцию, которая является другим блоком, и в этот момент я не думаю, что у меня больше есть доступ к «операции». Я думаю, что мой случай сработает только в том случае, если я подклассифицирую NSOperation. - person roocell; 21.11.2012
comment
я смог разрешить свой случай, пропустив операцию через мои блоки. спасибо - мне нравится этот подход, потому что он позволяет избежать подкласса NSOperation. - person roocell; 21.11.2012
comment
Это решение выглядит великолепно. Единственный небольшой вопрос, который у меня есть, заключается в том, должна ли переменная «операция» быть помечена __block? Я так не думаю, потому что значение переменной не нужно менять внутри блока. - person Jake; 21.12.2012
comment
@ Джейк Попробуй и увидишь! Это не должно работать, потому что operation будет nil (или мусорной памятью) во время определения блока, что означает, что внутри блока будет nil. Будьте осторожны с подвохом: ![nil isCancelled] всегда оценивается как YES, поэтому может выглядеть так, как будто он работает, если вы на самом деле никогда не пытаетесь отменить операцию. - person jemmons; 23.12.2012
comment
@jemmons Ваши рассуждения имеют смысл. теперь я понимаю, что ему нужен __block. Спасибо за разъяснения. - person Jake; 30.12.2012
comment
Эта реализация приведет к утечке памяти. Проверьте мое решение с решением проблемы утечки памяти. - person Aliaksandr Bialiauski; 07.02.2015

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

Пример кода:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSOperationQueue *q = [[NSOperationQueue alloc] init];
    [q addOperationWithBlock:^{
        [NSThread sleepForTimeInterval:10];
        NSLog(@"Block 1");
    }];
    [q addOperationWithBlock:^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"Block 2");
    }];
    [q cancelAllOperations];
    [NSThread sleepForTimeInterval:15];

    [pool drain];
    return 0;
}

Если вы удалите вызов cancelAllOperations, тогда блоки сработают, как и следовало ожидать.

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

person Joshua Smith    schedule 07.06.2011