【问题标题】:calling cancelAllOperations from nested NSOperations从嵌套的 NSOperations 调用 cancelAllOperations
【发布时间】:2016-06-14 11:49:38
【问题描述】:

我正在与以下情况作斗争,请多多包涵,因为我已尝试尽可能清楚地解释这一点:

我有一个类 CoummintyOperation,它是 GroupOperation 的子类。调用CommuityOperation 并将其添加到NSOperationQueue。 CommunityOperation 反过来又调用了一大堆 NSOperation,它们也是 GroupOperation 的子类,反过来又在其中调用 NSoperations。 我在 CommunityOperation 类中添加了 GroupOperations 的依赖项。 我正在处理的问题是,如果嵌套操作失败,我需要取消 CommunityOperations 类中的所有 NSOperations,但我无权访问添加 CommunityOperation 的 operationQueue 以调用 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
                ])
        }
}

DownloadGroupOperation 类又是 GroupOperation 的子类。它有两个操作 - 第一个是下载数据,第二个是解析数据:

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 在此方法的完成处理程序中:

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

【问题讨论】:

  • 源代码会有所帮助。你能举一个简单的例子来说明你在做什么吗?
  • @Dominic 有什么建议吗?

标签: ios swift nsoperation nsoperationqueue


【解决方案1】:

它应该以不同的方式工作。我会在每个NSOperation 执行结束时检查GroupOperation 中的isCancelled。如果操作被取消,则取消当前的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
            }
        }
    }

}

然后从您拥有的每个组操作的init 方法中调用addCancellationObservers

【讨论】:

【解决方案2】:

如果您使用 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 依赖项的工作方式。

换句话说,一个操作会在它的所有依赖完成后准备好,不管这些依赖是否成功。这是因为“成功”和“失败”是子类必须定义的。 OperationNSOperation 子类)通过没有任何错误完成来定义成功。

为了解决这个问题,添加一个条件,即必须没有依赖项失败。在操作中,这个条件被重命名以使其更清晰。但是,这个概念也存在于 Apple 示例代码中。

【讨论】:

  • 感谢@DaneilThorpe 的解释。我明白了你上面提到的内容,但你的推杆如此简洁真的很有帮助。基本上我当前的解决方案是在我的操作的 operationDidFinish:WithErrors 方法中,如果它以错误结束,我正在使用 NSNotifiications 在创建操作队列的类上调用 operationQueue.cancelAllOperations() 方法(显然这不是一个优雅的解决方案但它似乎正在工作)。
  • 关于您回答的第二部分,我不清楚在哪里以及添加什么内容,这样如果依赖关系失败,队列上的所有后续操作都应该取消。你能解释一下吗? (我下载了你的运营项目)谢谢
  • @Daniel.Thorpe 如果其中一个嵌套操作(例如 DownloadOperation)由于 cancelObserver 而被取消,我将如何取消源自主类的所有操作?
猜你喜欢
  • 2013-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-10
  • 2016-03-08
  • 1970-01-01
  • 2015-01-14
  • 1970-01-01
相关资源
最近更新 更多