Executing the NSOperation when all other operations in NSOperationQueue finished no matter whether they finished successfully or not

后端 未结 2 1851
傲寒
傲寒 2021-01-06 18:00

Hi I have a strange situation here :

OverView:

I am working on an app where user can initiate multiple operations and all these operations w

2条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-06 18:29

    Never mind I figured it out :)

    Setting the finished status to true and false triggers the KVO of NSOperationQueue and hence either starts or cancels the operation of dependent operations.

    If I want my operation to execute at any point whether the dependency operations finished successfully or not I can't make use of finished flag. In this case finished flag should always be true to indicate operation finished its execution.

    But how will I ensure the management of decency chain for those operations that have dependencies set and really depends whether the previous operation was successful or not ?? Simple I added another variable called finishedSuccessfully to my NSOperationSubclass.

    When a operation fails though it sets the finished flag to true it will set finishedSuccessfully to false. This will cause the dependent operations start method to get called.

    In the start method of dependent operation, it will iterate over all the dependency operations and checks has all of them finished with finishedSuccessfully = true.

    If yes that means all the dependency operations have finished execution and finished it successfully so it can start execution. On the other hand if any one of them has finishedSuccessfully = false, that means operation finished executing but failed to do whatever it was supposed to do hence this operation should also stop itself and inform its dependents that it finished with finishedSuccessfully = false.

    Summary :

    1. Operations will execute only after the execution of all the dependency operations finished executing no matter whether they finished successfully or not.

    2. Operations which are actually concerned about the execution status of their dependency operations will check for the status and then finally decides whether to continue execution or not.

    Dependency chain is maintained as well as the confirmation that sync operation executes as well :)

    Here is my implementation :

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

提交回复
热议问题