2016-06-14 4 views
0

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

У меня есть класс CoummintyOperation который является подклассом GroupOperation. CommuityOperation вызывается и добавляется в NSOperationQueue. CommunityOperation, в свою очередь, вызывает целую группу NSOperations, которые также являются подклассами GroupOperation и, в свою очередь, вызывают NSoperations внутри них. Я добавил зависимости для GroupOperations в классе CommunityOperation. Проблема, с которой я столкнулся, заключается в том, что если вложенная операция не удалась, мне нужно отменить все NSOperations в классе CommunityOperations, но у меня нет доступа к операцииQueue, к которой была добавлена ​​CommunityOperation, чтобы вызвать метод cancelAllOperations.

Может ли кто-нибудь помочь мне и объяснить, как я могу назвать этот метод, отмените все операции этого класса (и, следовательно, все вложенные операции) и выведете пользователю сообщение об ошибке.

Заранее спасибо

Вот некоторые примеры кода, чтобы помочь объяснить мою проблему: CommunityOperation получает положенным на operationQueue из другого класса (не входит в комплект)

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) 
    } 
} 

MenuOperation класса, который вложен операций в это также:

class UpdateMenuOperation: GroupOperation { 

    let downloadGroupsOperation: DownloadGroupsOperation 
    let downloadMembersOperation: DownloadMembersOperation 

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

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

Загрузить класс GroupOperation снова является подклассом GroupOperation. Он имеет 2 операции - первая для загрузки данных и второй для анализа данных:

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]) 
    } 
} 

И, наконец (Уф) класс DownloadOperation использует NSURLSession, и метод downloadTaskWithURL, то в обработчике завершения этого метода, что я хочу называть cancelAllOperations на главной operatioQueue, если возвращается ошибка:

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* 
     } 
    } 
} 
+0

Исходный код поможет. Можете ли вы привести краткий пример того, что вы делаете? – Dominic

+0

@ Dominic любые предложения? – mrcurious

ответ

0

Он должен работать в немного по-другому пути. Я проверил бы isCancelled от GroupOperation к концу каждого исполнения NSOperation. Если операция была отменена, отмените ток GroupOperation и так далее. В итоге ваш CommunityOperation также должен быть отменен.

Вот грубая реализация предлагаемого решения:

extension GroupOperation { 

    func addCancellationObservers() { 
     self.operations.forEach() { $0.willCancelObservers.append() { [unowned self] operation, errors in 
      self.cancel() // cancel the group operation. will force it to cancel all child operations 
      } 
     } 
    } 

} 

Затем вызовите addCancellationObservers из init метода каждой группы операций у вас есть.

+0

не могли бы вы привести пример, пожалуйста, я не следую тому, что вы говорите. Я обновил свой вопрос с помощью кода. – mrcurious

+0

Класс GroupOperations не имеет переменной массива операций – mrcurious

+0

Используете ли вы самозаписываемое 'GroupOperations' или настраиваемое решение, например https://github.com/danthorpe/Operations? – sgl0v

0

Если вы используете образец кода Apple (или https://github.com/danthorpe/Operations, который является эволюцией этого проекта), вы можете отсортировать его, присоединив условие к вашим операциям, имеющим зависимости.

Вот инициализации вашего верхнего уровня GroupOperation

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]) 
} 

Чтобы объяснить, что здесь происходит ... NSOperation не имеет понятия «провал». Операции всегда «завершаются», но завершились ли они успешно или неудачно, не влияет на то, как работают зависимости NSOperation.

Иными словами, операция будет готова, когда все ее зависимости закончатся независимо от того, были ли эти зависимости успешными. Это связано с тем, что «успех» и «отказ» - это то, что должен определить подкласс. Operation (подкласс NSOperation) определяет успех, закончив без ошибок.

Чтобы устранить это, добавьте условие, при котором никакие зависимости не должны были сработать. В Операции это условие получило переименование, чтобы сделать его более ясным. Но понятие существует и в образце кода Apple.

+0

Спасибо за это объяснение @DaneilThorpe. Я понял, что вы упомянули выше, но ваш подход настолько кратко помогает. В основном мое текущее решение находится в методах 'operationDidFinish: WithErrors' для моих операций, если он заканчивается ошибкой. Я использую NSNotifiications для вызова метода' operationQueue.cancelAllOperations() 'класса, создавшего очередь операций (очевидно, это не является изящным решением, но, похоже, он работает). – mrcurious

+0

Что касается второй части вашего ответа, я не понимаю, где и что добавить, что если зависимость не удалась, все последующие операции в очереди должны отменить. Можете ли вы пролить свет на это, пожалуйста. (Я загрузил ваш проект Operations). Спасибо. – mrcurious

+0

@ Daniel.Thorpe, если одна из вложенных операций (например, DownloadOperation) была отменена из-за cancelObserver, как бы я отменил все операции, происходящие из основного класса? – mrcurious