Как заполучить выполняемую в настоящее время NSOperation? - PullRequest
11 голосов
/ 07 сентября 2011

Есть ли эквивалент [NSOperationQueue currentQueue] или [NSThread currentThread] для NSOperation?

У меня довольно сложная модель предметной области, где тяжелая обработка происходит довольно глубоко в стеке вызовов. Чтобы своевременно отменить операцию, мне нужно было бы передать NSOperation в качестве параметра каждому методу, пока я не достигну точки, где я хочу прервать более продолжительный цикл. Используя потоки, я мог бы использовать [[NSThread currentThread] isCancelled], поэтому было бы удобно использовать эквивалент NSOperation, к сожалению, есть только, казалось бы, бесполезный [NSOperationQueue currentQueue].

Ответы [ 6 ]

7 голосов
/ 20 октября 2015

Придумал расширение в swift, которое возвращает запущенные операции

extension NSOperationQueue {
    public var runningOperations: [NSOperation] {
        return operations.filter {$0.executing && !$0.finished && !$0.cancelled}
    }
}

Затем вы можете забрать первый

if let operation = aQueue.runningOperations.first {}
4 голосов
/ 08 сентября 2011

Нет, нет способа найти выполняемую в данный момент операцию.

Два способа решения вашей проблемы:

  1. Операции - это объекты.Если вам нужен объект A для связи с объектом B, вам нужно организовать, чтобы A имел ссылку на B. Есть много способов сделать это.Один из способов - передать операцию каждому объекту, который должен знать об этом.Другое - использовать делегирование.Третье - сделать операцию частью более крупного «контекста», который передается каждому методу или функции.Если вы обнаружите, что вам нужно передать ссылку от одного объекта через несколько других, просто чтобы передать ее объекту, который, наконец, будет его использовать, это ключ, который вы должны подумать о перестановке кода.

  2. Пусть метод "тяжелого подъема" вернет некоторое значение, которое передается по цепочке вызовов.Вам не обязательно нужен тяжелый метод для вызова [currentOperation cancel] для достижения вашей цели.На самом деле, было бы лучше, если бы он возвращал какое-то значение, которое, как понимает операция, означает «работа выполнена, остановитесь сейчас», потому что он может проверить это возвращаемое значение и немедленно выйти, а не вызывать -isCancelled время от времени.чтобы узнать, была ли она отменена.

3 голосов
/ 07 сентября 2011

Это не очень хорошая идея. Операции обычно отменяются их очередью. В методе main () операции вы можете периодически проверять, отменено ли self (скажем, каждый n отключается в цикле или в начале каждого основного блока команд), и прерывать, если это так.

Чтобы ответить на отмену (скажем, некоторый элемент пользовательского интерфейса, связанный с состоянием операции или очереди), вы используете наблюдение значения ключа (KVO), чтобы ваш контроллер наблюдал свойства запуска, завершения и отмены операций (при необходимости) затем установите состояние вашего пользовательского интерфейса (всегда в главном потоке) при обновлении этих ключей. Согласно комментариям JeremyP, важно отметить, что уведомления KVO поступают из потока операции, и пользовательский интерфейс должен (почти) всегда обрабатываться в потоке main , поэтому вам необходимо использовать методы -performSelectorOnMainThread ... для обновите свой фактический пользовательский интерфейс, когда получите уведомление об изменении состояния KVO.

Что вы действительно пытаетесь сделать? То есть, почему вы чувствуете, что другие части вашего приложения должны знать непосредственно о текущей операции?

1 голос
/ 11 июня 2017

Для этого можно использовать комбинацию [NSOperationQueue currentQueue] и [NSThread currentThread].

По сути, вам нужно пройтись по операциям в currentQueue и найти операцию, выполняемую в currentThread.

NSOperation не предоставляет доступ к потоку, в котором он запущен, поэтому вам нужно добавить это свойство самостоятельно и назначить его.

Возможно, вы уже подклассифицируете NSOperation и предоставляете main, поэтому добавьте свойство 'thread' к этому подклассу:

@interface MyOperation : NSOperation
    @property(nonatomic,strong) NSThread *thread ;
@end

Затем в вашем 'main' назначьте текущий поток этому свойству

myOperation.thread = [NSThread currentThread]

Затем вы можете добавить метод currentOperation:

+(MyOperation *)currentOperation
{
    NSOperationQueue *opQueue = [NSOperationQueue currentQueue] ;
    NSThread *currentThread = [NSThread currentThread] ;

    for( MyOperation *op in opQueue.operations ) {
        if( [op isExecuting] && [op respondsToSelector:@selector(thread)] ) {
                if( op.thread == currentThread ) {
                    return ( op ) ;
                }
            }
        }
    }

    return nil ;
}
1 голос
/ 15 января 2012

Вы можете сохранить текущую операцию в словаре потоков. Просто не забудьте избавиться от него перед выходом. Вы можете безопасно использовать поток dict, если вы создали объект.

0 голосов
/ 08 сентября 2011

Как узнать, какую операцию вы хотите отменить?Когда вы дойдете до точки, которую хотите отменить, просто позвоните в [myQueue operations] и выполняйте операции, пока не найдете те, которые вы сейчас хотите отменить.Я думаю, если у вас есть миллионы операций (или тысячи), это может не сработать.

[операции myQueue] являются потокобезопасными - снимок содержимого очереди.Вы можете погрузиться в нее довольно быстро, отменив по желанию.

Другой способ: NSOperationQueue не является одиночным, поэтому вы можете создать Q, в котором есть 200 заданий, а затем отменить все 20, просто получив этот Q и отменив их все.Сохраните Q в словаре в главном потоке, и тогда вы сможете получить задания, которые вы хотите отменить из диктата, и отменить их все.то есть у вас есть 1000 видов операций, и в той точке кода, где вы понимаете, что вам не нужна определенная задача, вы просто получаете Q для этого вида и просматриваете его, чтобы найти задания для отмены.

...