当NSOperationQueue中的所有其他操作完成时,执行NSOperation,无论它们是否成功完成

嗨,我在这里有一个奇怪的情况:

概述:

我正在开发一个应用程序,用户可以启动多个操作,所有这些操作将在后台线程上运行,因此不会阻止用户界面。 其中一些操作是相互依赖的,有些则不是。 所以为了确保只有在所有必要的依赖项操作完成后才执行操作,使用Operation的依赖项属性执行。 我正在使用asynchronous操作。

这是我的实现:

import UIKit import CoreData import SwiftyJSON class VMBaseOperation: NSOperation { var finishedStatus : Bool = false var executionStatus : Bool = false var retryCount : Int = 0 private (set) var requestToQueue : BaseRequest? = nil var vmOperationCompletionBlock: ((JSON?) -> Void)? var vmOperationFailureBlock: ((WebResponseError?) -> Void)? override init() { super.init() } convenience init(withVMRequest request : BaseRequest) { self.init() requestToQueue = request } override func start() { if self.cancelled { self.finished = true return } NSThread.detachNewThreadSelector(#selector(main), toTarget: self, withObject: nil) self.executionStatus = true } override func main() { if self.cancelled { return } self.hitWebService() } func hitWebService(){ let webserviceManager = WebServiceManager() webserviceManager.getResponseFromRequest(requestToQueue!) { (requset, response, data, error) in let error = WebResponseError.checkResponse(response, request: requset, error: error) if error != nil { if error == WebResponseError.NO_INTERNET { if self.vmOperationFailureBlock != nil { self.vmOperationFailureBlock!(error) } self.operationFailed() } else{ self.retryCount += 1 if self.retryCount == 3 { if self.vmOperationFailureBlock != nil { self.vmOperationFailureBlock!(error) } self.operationFailed() } else{ self.hitWebService() } } } else{ if data == nil { self.retryCount += 1 if self.retryCount == 3 { if self.vmOperationFailureBlock != nil { self.vmOperationFailureBlock!(nil) } self.operationFailed() } else{ self.hitWebService() } } else{ let json = JSON(data: data!) if self.vmOperationCompletionBlock != nil { self.vmOperationCompletionBlock!(json) } self.operationCompleted() } } } } override var finished: Bool { get{ return finishedStatus } set{ self.willChangeValueForKey("isFinished") finishedStatus = newValue self.didChangeValueForKey("isFinished") } } override var executing: Bool { get{ return executionStatus } set{ self.willChangeValueForKey("isExecuting") executionStatus = newValue self.didChangeValueForKey("isExecuting") } } override var asynchronous: Bool{ get{ return true } set{ self.willChangeValueForKey("isAsynchronous") self.asynchronous = true self.didChangeValueForKey("isAsynchronous") } } func operationCompleted(){ self.executing = false self.finished = true } func operationFailed(){ self.executing = false self.finished = false } } 

它能做什么 :

每个操作接受一个Web请求,并尝试从服务器获取数据,如果失败,则尝试3次,最后通过调用operationFailed方法将其完成状态设置为false,并通过停止所有依赖操作永远停止执行。如果成功,则通过调用operationCompleted将其完成状态更改为true,从而触发剩余相关操作的执行。

什么是问题:

依赖就像一个魅力。 没有问题。 现在,当操作队列中的所有操作完成执行时,无论是否成功完成,都需要从服务器同步数据。

最简单的方法是创build一个操作来同步来自服务器的数据,并将其作为依赖操作添加到所有添加到operationQueue的操作中。

但是由于操作的上述性质,即使一个操作失败了所有依赖操作的执行(如预期的那样),但是因为来自服务器操作的同步数据也是依赖操作,所以即使一个操作操作失败:(

我需要的 :

在维护我上面提到的依赖关系的时候,我需要知道如何执行一个操作,当操作队列中的所有操作完成执行时,无论它们是成功还是失败,都将同步来自服务器的数据。

这甚至可能:(请帮助我,谢谢提前。

随着您的实施operationFailed

 func operationFailed(){ self.executing = false self.finished = false } 

你打破了NSOperation的原生逻辑:

操作依赖关系

依赖性是以特定顺序执行操作的一种便捷方式。 您可以使用addDependency:和removeDependency:方法为操作添加和删除依赖项。 默认情况下,具有依赖关系的操作对象在所有依赖操作对象完成执行之前不会被视为准备就绪。 但是,一旦最后的依赖操作完成,操作对象就准备好并能够执行。

NSOperation支持的依赖关系不区分依赖操作是成功还是失败。 (换句话说,取消一个操作同样会将其标记为已完成。) 由您决定是否 应在依赖操作 被取消或未成功完成任务的 情况下 执行具有 依赖关系的操作 。 这可能需要您将一些额外的错误跟踪function合并到您的操作对象中。

如果操作失败,devise应该完成。 但它可以标记自己(某些特殊的财产或cancelled )。

应该检查相关的操作是否可以启动。 像下面的东西应该做的工作:

 var requireDependencesCompletion: Bool = true override var ready: Bool { if requireDependencesCompletion { for op in self.dependencies { if op.cancelled { cancel() } } super.ready } 

这里我们重写ready属性来确定应该做什么。 如果requireDependencesCompletiontrue ,则操作将检查其所有依赖关系,并在其中一个取消时自行取消。

为您的典型操作设置requireDependencesCompletiontrue ,并将您的屏障操作设置为false ,以便在任何情况下启动。

没关系,我知道了:)

将完成状态设置为true和false会触发NSOperationQueue的KVO,因此可以启动或取消依赖操作的操作。

如果我想让我的操作在任何时候执行,依赖操作是否成功完成,我不能使用完成标志。 在这种情况下,完成标志应始终为真,以指示操作完成其执行。

但是如何确保那些有依赖关系的操作的正派链pipe理,真正取决于以前的操作是否成功? 简单的我添加了一个名为finishedSuccessfully的variables到我的NSOperationSubclass。

当一个操作失败,虽然它将完成标志设置为true,它将设置finishedSuccessfully为false。 这将导致依赖操作启动方法被调用。

在依赖操作的开始方法中,它将遍历所有的依赖操作,并检查是否全部完成了finishedSuccessfully = true。

如果是这意味着所有的依赖操作都已经完成并成功完成,所以它可以开始执行。 另一方面,如果其中任何一个已经成功完成= false,则意味着操作完成执行,但是没有做任何它应该做的事情,因此这个操作也应该停止自己并且通知它的依赖者它已经完成了成功=假。

总结:

  1. 只有在执行完所有的依赖操作后,操作才会执行,无论它们是否成功完成。

  2. 实际关心其依赖操作的执行状态的操作将检查状态,然后决定是否继续执行。

维护依赖关系链以及同步操作执行的确认:)

这是我的实现:

 import UIKit import CoreData import SwiftyJSON class VMBaseOperation: NSOperation { var finishedSuccessfully : Bool = false var finishedStatus : Bool = false var executionStatus : Bool = false var retryCount : Int = 0 private (set) var requestToQueue : BaseRequest? = nil var vmOperationCompletionBlock: ((JSON?) -> Void)? var vmOperationFailureBlock: ((WebResponseError?) -> Void)? override init() { super.init() } convenience init(withVMRequest request : BaseRequest) { self.init() requestToQueue = request } override func start() { if self.cancelled { self.finished = true return } //those operations which actually wants to know if all its dependency operations finished successfully or not can create a subclass of this class override start method and add the below code for operation in self.dependencies { if (operation as! VMBaseOperation).finishedSuccessfully == false { self.operationFailed() return } } //others can ignore. NSThread.detachNewThreadSelector(#selector(main), toTarget: self, withObject: nil) self.executionStatus = true } override func main() { if self.cancelled { return } self.hitWebService() } func hitWebService(){ let webserviceManager = WebServiceManager() webserviceManager.getResponseFromRequest(requestToQueue!) { (requset, response, data, error) in let error = WebResponseError.checkResponse(response, request: requset, error: error) if error != nil { if error == WebResponseError.NO_INTERNET { if self.vmOperationFailureBlock != nil { self.vmOperationFailureBlock!(error) } self.operationFailed() } else{ self.retryCount += 1 if self.retryCount == 3 { if self.vmOperationFailureBlock != nil { self.vmOperationFailureBlock!(error) } self.operationFailed() } else{ self.hitWebService() } } } else{ if data == nil { self.retryCount += 1 if self.retryCount == 3 { if self.vmOperationFailureBlock != nil { self.vmOperationFailureBlock!(nil) } self.operationFailed() } else{ self.hitWebService() } } else{ let json = JSON(data: data!) if self.vmOperationCompletionBlock != nil { self.vmOperationCompletionBlock!(json) } self.operationCompleted() } } } } override var finished: Bool { get{ return finishedStatus } set{ self.willChangeValueForKey("isFinished") finishedStatus = newValue self.didChangeValueForKey("isFinished") } } override var executing: Bool { get{ return executionStatus } set{ self.willChangeValueForKey("isExecuting") executionStatus = newValue self.didChangeValueForKey("isExecuting") } } override var asynchronous: Bool{ get{ return true } set{ self.willChangeValueForKey("isAsynchronous") self.asynchronous = true self.didChangeValueForKey("isAsynchronous") } } func operationCompleted(){ self.executing = false self.finished = true } func operationFailed(){ self.finishedSuccessfully = false self.operationCompleted() } func operationSucceeded(){ self.finishedSuccessfully = true self.operationCompleted() } }