ios - llamando a cancelAllOperations desde NSOperations anidadas


Estoy luchando con la siguiente situación, por favor tengan paciencia conmigo ya que he tratado de explicar esto lo más claramente posible:

Tengo una clase CoummintyOperation que es una subclase de GroupOperation. Se llama a CommuityOperation y se agrega a NSOperationQueue. CommunityOperation, a su vez, está llamando a un montón de NSOperations que también son subcasos de GroupOperation y, a su vez, están llamando a NSoperations dentro de ellas. He agregado dependencias para GroupOperationsen la clase CommunityOperation. El problema con el que estoy lidiando es si falla una operación anidada, necesito cancelar TODAS LAS NSOperations en la clase CommunityOperations, pero no tengo acceso a la cola de operación a la que se agregó CommunityOperation para llamar al método cancelAllOperations.

¿Alguien puede ayudarme y explicar cómo puedo llamar a este método, cancelar todas las operaciones en esta clase (y por lo tanto todas las operaciones anidadas) y mostrar un mensaje de error al usuario?

Gracias en advance

Aquí hay un código de muestra para ayudar a explicar mi problema: CommunityOperation se pone en una OperationQueue de otra clase (no incluida)

public class CommunityOperation: GroupOperation {

    var updateOperation: UpdateOperation!
    var menuOperation: MenuOperation!
    var coreDataSaveOperation: CoreDataSaveOperation!

    var hasErrors = false

    public init() {

        super.init(operations: [])

        updateOperation = UpdateOperation()
        menuOperation = MenuOperation()
        coreDataSaveOperation = CoreDataSaveOperation()
        coreDataSaveOperation.addDependencies([updateOperation, menuOperation])

        self.addOperation(updateOperation)
        self.addOperation(menuOperation)
        self.addOperation(coreDataSaveOperation)
    }
}

Clase MenuOperation, que también tiene Operaciones anidadas:

class UpdateMenuOperation: GroupOperation {

    let downloadGroupsOperation: DownloadGroupsOperation
    let downloadMembersOperation: DownloadMembersOperation

    init() {
            downloadGroupsOperation = DownloadGroupsOperation()
            downloadMembersOperation = DownloadMembersOperation(])

            super.init(operations: [downloadGroupsOperation,
                downloadMembersOperation
                ])
        }
}

La clase DownloadGroupOperation es nuevamente una subclase de GroupOperation. Tiene 2 operaciones: la primera para descargar datos y la segunda para analizar los datos:

class DownloadTopGroupsOperation: GroupOperation {
    let downloadOperation: DownloadOperation
    let importTopGroupsOperation: ImportOperation

    init() {
        downloadOperation = DownloadOperation()
        importOperation = ImportOperation()
        importOperation.addDependency(downloadOperation)
        importOperation.addCondition(NoCancelledDependencies())

        super.init(operations: [downloadOperation, importOperation])
    }
}

Y finalmente (vaya) la clase DownloadOperation usa una NSURLSession y el método downloadTaskWithURL, es en el controlador de finalización de este método donde quiero llamar a cancelAllOperations en la operatioQueue principal si se devuelve un error:

class DownloadOperation: GroupOperation {
    init() {
        super.init(operations: [])
        if self.cancelled {
            return
       }
        let task = session.downloadTaskWithURL(url) { [weak self] url, response, error in
            self?.downloadFinished(url, response: response as? NSHTTPURLResponse, error: error)
        }
    }

    func downloadFinished(url: NSURL?, response: NSHTTPURLResponse?, error: NSError?) {

       if error {
         *cancel allOperations on queue*
       }
    }
}


------------Respuesta------------

Debería funcionar de una manera un poco diferente. Verificaría isCancelled de GroupOperation al final de cada ejecución de NSOperation. Si se canceló la operación, cancele la GroupOperation actual y así sucesivamente. Al final, su CommunityOperation también debería cancelarse.

Aquíes la implementación aproximada de la solución propuesta:

extension GroupOperation {

    func addCancellationObservers() {
        self.operations.forEach() { 
init() {

    updateOperation = UpdateOperation()
    menuOperation = MenuOperation()
    coreDataSaveOperation = CoreDataSaveOperation()
    coreDataSaveOperation.addDependencies([updateOperation, menuOperation])

    // Attach a condition to ensure that all dependencies succeeded
    coreDataSaveOperation.addCondition(NoFailedDependenciesCondition())

    super.init(operations: [updateOperation, menuOperation, coreDataSaveOperation])
}
.willCancelObservers.append() { [unowned self] operation, errors in self.cancel() // cancel the group operation. will force it to cancel all child operations } } } }

Luego llame a addCancellationObservers desde el método init de cada operación de grupo que tenga.



------------Respuesta------------

si está utilizando el código de muestra de Apple (o https://github.com/danthorpe/Operations, que es la evolución de ese proyecto), puede resolver esto agregando una condición a sus operaciones que tienen dependencias.

Aquí está el inicio de su GroupOperation de nivel superior

1008611

Para explicar lo que está pasando aquí... NSOperation no tiene el concepto de "fracaso". Las operaciones siempre "terminan", pero si terminaron correctamente o fallaron no afecta el funcionamiento de las dependencias de NSOperation.

En otras palabras, una operación estará lista cuando finalicen todas sus dependencias, independientemente de si esas dependencias se realizaron correctamente. Esto se debe a que el "éxito" y el "fracaso" son algo que la subclase debe definir. Operación (la subclase NSOperation) define el éxito porhaber terminado sin ningún error.

Para solucionar esto, agregue una condición de que ninguna dependencia debe haber fallado. En Operaciones, esta condición se renombró para que quede más clara. Pero el concepto también existe en el código de ejemplo de Apple.

Etiquetas: nsoperation nsoperationqueue swift ios

Artículos relacionados:

ios: recuperación de la matriz bool de NSUserdefaults en Swift

toque de cacao - Haz que la imagen encaje dentro del botón en iOS