2011-09-07 12 views
9

¿Hay un equivalente a [NSOperationQueue currentQueue] o [NSThread currentThread] para NSOperation?¿Cómo obtener la NSOperation actualmente en ejecución?

Tengo un modelo de dominio bastante complejo donde el procesamiento pesado ocurre bastante profundo en la pila de llamadas. Con el fin de cancelar oportunamente una operación, necesitaría pasar el NSOperation como parámetro para cada método hasta que llegue al punto en el que quiero interrumpir un ciclo de ejecución más largo. Usando hilos podría usar [[NSThread currentThread] isCancelled] por lo que parece conveniente si hay un equivalente para NSOperation, desafortunadamente solo existe el aparentemente inútil [NSOperationQueue currentQueue].

Respuesta

3

Esto no es una buena idea. Las operaciones generalmente son canceladas por su cola. Dentro del método main() de la operación, puede verificar periódicamente si self se cancela (por ejemplo, cada n dispara a través de un bucle, o al comienzo de cada bloque principal de comandos) y cancelar si es así.

Para responder a una cancelación (por ejemplo, algún elemento de IU relacionado con el estado de la operación o de la cola), utiliza la observación del valor de clave (KVO) para que el controlador observe las propiedades de inicio, finalización y cancelación canceladas (según sea necesario)), luego configure el estado de su UI (siempre en el hilo principal) cuando esas claves se actualicen. Según los comentarios de JeremyP, es importante tener en cuenta que las notificaciones de KVO provienen del hilo de la operación y la IU debe (casi) siempre manipularse en el hilo principal, por lo que deberá usar los métodos -performSelectorOnMainThread ... para actualizar su UI real cuando reciba un cambio de estado, la nota de KVO sobre sus operaciones.

¿Qué estás realmente tratando de hacer? Es decir, ¿por qué cree que otras partes de su aplicación necesitan saber directamente sobre la operación actual?

+0

-1 me temo. Nada de esto va a funcionar. La configuración de la propiedad cancelada de una operación no tendrá efecto a menos que la operación compruebe periódicamente la propiedad isCancelled. Ciertamente, KVO no funcionará porque las notificaciones KVO se reciben en el mismo hilo en el que se envían. – JeremyP

+3

Errr ... ¿has leído mi publicación antes de la votación? Observar estas propiedades es * exactamente * cómo se hacen estas cosas. Observa el cambio de estado y luego utiliza -performSelectorOnMainThread ... para hacer cualquier cosa que necesite hacer en el hilo principal. "Nada de esto va a funcionar" es una novedad para mí, ya que tengo varias aplicaciones haciendo exactamente eso. Además, nunca dije que * estableciera * la cancelación. De hecho, específicamente dije que la cola cancela la operación y la operación comprueba este estado periódicamente y deja de funcionar si es verdadero. –

+0

Lo que sucede es: cola cancela ops -> publicaciones op Nota de KVO de isCancelled, maneja deteniéndose a sí mismo -> Observer (algunas de tus controladoras) notas cambian, y si tiene trabajo que hacer, lo hace en el hilo principal. Funciona todo el tiempo. El hecho de que su controlador esté enviado por mensaje en otro hilo no significa que no pueda manejarlo. Si tiene que hacer algo en el hilo principal, avance y envíe algo sobre el hilo principal. –

0

¿Cómo sabe qué operación desea cancelar? Cuando llegue al punto que desea cancelar, simplemente llame a [operaciones myQueue] y realice las operaciones hasta que encuentre las que desea cancelar. Supongo que si tienes millones de operaciones (o miles) esto podría no funcionar.

[operaciones myQueue] es seguro para subprocesos: una instantánea del contenido de la cola. Puedes bucear a través de ella cancelando bastante rápido a voluntad.

Otra forma: NSOperationQueue no es un singleton, por lo que puede crear una Q que tenga aproximadamente 200 trabajos en ella, y luego cancelar los 20 simplemente obteniendo esa Q y cancelando todas. Almacene las Q en un diccionario en el hilo principal, y luego puede obtener las tareas que desea cancelar desde el diccionario y cancelarlas todas. es decir, tiene 1000 tipos de operaciones y en el punto en el que se da cuenta de que no necesita una determinada tarea, solo obtiene la Q para ese tipo, y revise los trabajos para cancelar.

4

No, no hay un método para encontrar la operación que se está ejecutando actualmente.

dos maneras de resolver su problema:

  1. Las operaciones son objetos. Si necesita el objeto A para hablar con el objeto B, tendrá que hacer arreglos para que A tenga una referencia a B. Hay muchas maneras de hacerlo. Una forma es pasar la operación a lo largo de cada objeto que necesita saber al respecto. Otra es usar delegación. Un tercero es hacer que la operación forme parte de un "contexto" más amplio que se transfiere a cada método o función. Si encuentra que necesita pasar una referencia de un objeto a través de varios otros simplemente para obtener el objeto que finalmente lo usará, esa es una pista que debe considerar para reorganizar su código.

  2. Haga que el método de "elevación pesada" devuelva algún valor que se pase por la cadena de llamadas. No necesariamente necesita el método de levantamiento pesado para llamar al [currentOperation cancel] para lograr su objetivo. De hecho, sería mejor que devuelva algún valor que la operación comprenda que signifique "el trabajo está hecho, deténgase ahora" porque puede verificar ese valor de retorno y salir inmediatamente en lugar de tener que llamar al -isCancelled de vez en cuando para encontrar si ha sido cancelado

1

Puede almacenar la operación actual en el diccionario de subprocesos. Solo recuerde deshacerse de él antes de salir. Puede usar el dict del hilo de forma segura si creó el objeto.

4

se acercó con una extensión en veloz que devuelve las operaciones que se ejecutan

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

A continuación, puede recoger el primero

if let operation = aQueue.runningOperations.first {} 
+0

Disimulado, pero lo probé y funciona con bastante elegancia, incluso en todas las clases desde la declaración Swift hasta que se llama en Objective-C usando [[[NSOperationQueue currentQueue] runningOperations] objectAtIndex: 0]. – eGanges

1

Se puede utilizar una combinación de [NSOperationQueue currentQueue] & [ NSThread currentThread] para lograr esto.

Esencialmente, debe recorrer las operaciones en la corriente actual y buscar la operación que se ejecuta en el actualThread.

NSOperation no proporciona acceso al subproceso en el que se está ejecutando, por lo que debe agregar esa propiedad y asignarla.

es probable que ya la subclasificación NSOperation y proporcionando un principal, por lo que añadir una propiedad 'hilo' a la subclase:

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

Luego, en su 'principal' asignar el hilo actual a esa propiedad

myOperation.thread = [NSThread currentThread] 

a continuación, puede añadir un método de '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 ; 
} 
Cuestiones relacionadas