NSOperation не отменяется должным образом

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

Итак, у меня есть сценарий, в котором на экране может быть несколько контроллеров представления. Каждый контроллер представления будет создавать операцию синтаксического анализа при загрузке и добавлять ее в очередь. Я разрешаю 2 одновременные операции обработки, установив maxConcurrentOperationCount. Каждый контроллер представления создает операцию обработки, помещает ее в одноэлементную очередь и сохраняет операцию как свойство, поэтому имеет дескриптор для нее.

Если контроллер представления должен уйти в ответ на действие Delete, инициированное пользователем, я использую свойство NSOperation в методе dealloc моего контроллера представления, чтобы отменить операцию:

-(void)dealloc{
    [self.currentOperation cancel];
    [super dealloc];
}

В моем подклассе NSOperation я проверяю свойство isCancelled в нескольких местах (в основном перед значительными фрагментами длительной работы) свойство isCancelled и пытаюсь ответить на него:

if([self isCancelled]){
    // Perform cleanup
    return;
}

Проблема в том, что свойство isCancelled оценивается как false, и операция продолжается, в конечном итоге вызывая Core Data, чтобы попытаться получить данные, которые были удалены. Я вижу, что это происходит, даже когда я размещаю проверку isCancelled непосредственно перед запросом на выборку Core Data.

У меня есть обходной путь, чтобы предотвратить сбой приложения, но я думаю, что могу ошибиться в реализации. Есть ли другой способ сохранить дескриптор операции во время ее обработки, чтобы при необходимости отменить ее? Мой метод не сохраняет надлежащий дескриптор операции и не препятствует ее правильной отмене?


person Mark Struzinski    schedule 10.08.2011    source источник
comment
Если вы не переопределили метод отмены в своем NSOperation, тогда isCancelled должен оценить значение true после того, как вы вызовете cancel. Убедитесь, что значение self.currentOperation не равно нулю к моменту достижения dealloc.   -  person Joe    schedule 10.08.2011


Ответы (1)


Вы не можете использовать такую ​​логику в dealloc.

Во-первых, dealloc должен вызывать в последней строке dealloc super. Как только это будет сделано, объект исчезнет, ​​и все последующее поведение обмена сообщениями будет неопределенным (произойдет сбой).

Также очень вероятно, что очередь сохранит операцию, что сделает отмену в dealloc бессмысленной, потому что dealloc не может быть вызван до тех пор, пока очередь не освободится (если ваше управление памятью не испорчено).

Вам необходимо полностью отделить логику отмены / аннулирования от управления памятью.

person bbum    schedule 10.08.2011
comment
Извините, я не включил весь метод dealloc. В конце я звоню [super dealloc]. Я пробовал вызвать отмену из нескольких разных мест. Изначально я пытался вызвать его при вызове метода Delete. Я всегда получал один и тот же результат. Чтобы прояснить, я вызывал это в методе dealloc контроллера представления, который сохранял эту конкретную операцию как свойство. Я неправильно с этим обращаюсь? - person Mark Struzinski; 10.08.2011
comment
Да - к моменту вызова dealloc граф объектов, связанный с освобождаемым объектом, находится в неопределенном состоянии (вы не знаете, какие объекты уже были освобождены, за исключением тех, которые этот объект имеет тяжело удерживается на). Вам необходимо полностью отделить логику отмены от высвобождения. - person bbum; 10.08.2011
comment
Можно ли отменить (из вашей операции), вызванную из пользовательского интерфейса? то есть из основного потока? Разве это не проблема, потому что isCancel можно вызвать из двух разных потоков, создающих состояние гонки? Спасибо за ответ. - person Ricardo; 23.01.2012