NSOperationQueue中的所有其他操作完成时,无论它们是否成功完成,都将执行NSOperation [英] Executing the NSOperation when all other operations in NSOperationQueue finished no matter whether they finished successfully or not

查看:77
本文介绍了NSOperationQueue中的所有其他操作完成时,无论它们是否成功完成,都将执行NSOperation的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里遇到一个奇怪的情况:

Hi I have a strange situation here :

概述:

我正在开发一个应用程序,用户可以在其中启动多个操作,并且所有这些操作都将在后台线程上运行,因此不会阻塞UI.这些操作中有一些是相互依赖的,而某些则不是.因此,为了确保仅在所有必要的依赖项操作完成执行后才使用Operation的依赖项属性来执行操作.我正在使用异步操作.

I am working on an app where user can initiate multiple operations and all these operations will run on a background thread hence will not block the UI. Some of these operations are dependent on each other and some are not. So in order to ensure that operation will execute only after all the necessary dependencies operations finished executing am using the dependency property of Operation. I am making use of Asynchronous operations.

这是我的实现:

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,从而触发其余依赖操作的执行.

each operation takes a web request and attempts to get the data from server and if it fails, it tries 3 times before finally setting its finished status to false by calling operationFailed method and there by stopping all the dependent operation from executing forever.On the other hand if it succeeds it changes its finished status to true by calling operationCompleted hence triggers the execution of remaining dependent operations.

问题是什么

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

Dependency works like a charm. No issue with that. Now I need to sync the data from server when all the operations in the operation queue finished executing no matter whether they finished successfully or not.

最简单的方法是创建一个操作以同步来自服务器的数据,并将其作为从属操作添加到添加到operationQueue的所有操作中.

Easiest way to do it is to create a Operation to sync the data from server and add it as dependent operation to all the operations added to operationQueue.

但是由于操作的上述性质,即使一个操作全部失败,也会停止执行所有从属操作(如预期的那样),但是由于我来自服务器操作的同步数据也是从属操作,因此它将永远不会执行即使一项操作失败:(

But because of the above mentioned nature of the operation, even if one operation fails all its stops the execution of all the dependent operations (as expected) but because my sync data from server operation is also a dependent operation it will never execute even if one operation fails :(

我需要什么:

在保持上面提到的依赖性的同时,我需要知道如何在操作队列中的所有操作成功执行之后,无论它们成功还是失败,都如何执行操作以同步服务器中的数据.

While maintaining the dependency I mentioned above I need to know how to execute an operation to sync the data from server when all the operations in operation queue finishes executing no matter whether they succeed or fail.

那有可能吗:(请帮帮我.提前谢谢.

Is that even possible :( Please help me out . Thanks in advance.

推荐答案

随着您的实现 operationFailed :

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

您破坏了NSOperation的本机逻辑:

you break NSOperation's native logic:

操作依赖项

依赖关系是在特定位置执行操作的便捷方式命令.您可以使用addDependency:和removeDependency:方法.默认情况下,一项操作具有依赖关系的对象直到其所有对象都准备就绪依赖操作对象已完成执行.最后一次从属操作完成,但是操作对象变为准备好并能够执行.

Dependencies are a convenient way to execute operations in a specific order. You can add and remove dependencies for an operation using the addDependency: and removeDependency: methods. By default, an operation object that has dependencies is not considered ready until all of its dependent operation objects have finished executing. Once the last dependent operation finishes, however, the operation object becomes ready and able to execute.

NSOperation支持的依赖性在以下方面没有区别相关操作是成功完成还是失败.(换句话说,取消操作将其标记为已完成.)由您决定是否进行操作在依存操作的情况下应继续依存关系已被取消或未成功完成任务.这可能要求您合并一些其他错误跟踪功能进入您的操作对象.

The dependencies supported by NSOperation make no distinction about whether a dependent operation finished successfully or unsuccessfully. (In other words, canceling an operation similarly marks it as finished.) It is up to you to determine whether an operation with dependencies should proceed in cases where its dependent operations were cancelled or did not complete their task successfully. This may require you to incorporate some additional error tracking capabilities into your operation objects.

根据设计,如果操作失败,则应完成.但是它可以以某种方式标记自己(某些特殊属性或已取消的一种).

By design if operation fails it should finish. But it could mark itself somehow (some special property or a cancelled one).

相关操作应检查是否可以启动.像下面这样的事情应该可以完成这项工作:

Dependent operations should check is it possible to start. Something like the following should do the job:

var requireDependencesCompletion: Bool = true

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

在这里,我们重写 ready 属性来确定应执行的操作.如果 requireDependencesCompletion true ,则一个操作将检查其所有依赖关系,如果其中之一被取消,则将自身取消.

Here we override ready property to determine what should be done. If requireDependencesCompletion is true an operation will check all its dependences and cancel itself if one of them was cancelled.

将典型操作的 requireDependencesCompletion 设置为 true ,将 barrier 操作设置为 false ,以便启动无论如何.

Set requireDependencesCompletion to true for your typical operations and to false to your barrier operation so it will start in any case.

这篇关于NSOperationQueue中的所有其他操作完成时,无论它们是否成功完成,都将执行NSOperation的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆