runAction on SKNode does not complete

人走茶凉 提交于 2019-12-19 11:53:44

问题


I use a subclass NSOperation to obtain serial execution of SKAction as described in this question: How to subclass NSOperation in Swift to queue SKAction objects for serial execution?

I then modified the previous subclass in order to group animations for several nodes: https://stackoverflow.com/a/30600718/540780

At last, as I needed to run completion block after SKAction completed, I slightly modified the code by using an array of struct instead an array of tuples.

struct ActionData {
    let node:SKNode
    let action:SKAction
    let completion: () -> ()

    init (node:SKNode, action:SKAction, completion:() -> () = {}) {
        self.node = node
        self.action = action
        self.completion = completion
    }
}

class ActionOperation : NSOperation
{

    let _theActions:[ActionData]

    var _finished = false // Our read-write mirror of the super's read-only finished property
    var _executing = false // Our read-write mirror of the super's read-only executing property

    var _numberOfOperationsFinished = 0 // The number of finished operations


    /// Override read-only superclass property as read-write.
    override var executing:Bool {
        get { return _executing }
        set {
            willChangeValueForKey("isExecuting")
            _executing = newValue
            didChangeValueForKey("isExecuting")
        }
    }

    /// Override read-only superclass property as read-write.
    override var finished:Bool {
        get { return _finished }
        set {
            willChangeValueForKey("isFinished")
            _finished = newValue
            didChangeValueForKey("isFinished")
        }
    }


    // Initialisation with one action for one node
    //
    // For backwards compatibility
    //
    init(node:SKNode, action:SKAction) {
        let donnees = ActionData(node: node, action: action, completion: {})
        _theActions = [donnees]

        super.init()
    }

    init (lesActions:[ActionData]) {
        _theActions = lesActions

        super.init()
    }

    func checkCompletion() {
        _numberOfOperationsFinished++

        logGeneral.debug(">> Block completed: \(self._numberOfOperationsFinished)/\(self._theActions.count) " + self.name!)

        if _numberOfOperationsFinished ==  _theActions.count {
            self.executing = false
            self.finished = true
            logGeneral.debug("Operation Completed: " + self.name!)
        }

    }

    override func start()
    {
        if cancelled {
            finished = true
            return
        }

        executing = true

        if name == nil {
            name = "unknown"
        }


        _numberOfOperationsFinished = 0
        var operation = NSBlockOperation()

        var compteur = 0
        for actionData in _theActions {
            compteur++

            var actionName = "???"
            if let name = actionData.node.name {
                actionName = name
            }

            logGeneral.debug("operation : \(compteur)/\(self._theActions.count) " + self.name! + " " + actionName)
            operation.addExecutionBlock({
                actionData.node.runAction(actionData.action,completion:{
                    actionData.completion()
                    self.checkCompletion() })
            })
        }

        logGeneral.debug("Execute: " + self.name!)
        NSOperationQueue.mainQueue().addOperation(operation)

    }
}

The main idea is to elaborate animations by adding data of ActionData type, append them to an array and transmit this array to the ActionAnimation object.

In some random cases, some runAction doesn complete: they start but some of them randomly do not complete. Here is a typical log where 6 block started but only 5 completed:

start(): operation : 1/6 ???
start(): operation : 2/6 suppressionPion1
start(): operation : 3/6 suppressionPion2
start(): operation : 4/6 suppressionPion3
start(): operation : 5/6 suppressionPion4
start(): operation : 6/6 suppressionGroupe1
start(): Execute: animerSupprimer
checkCompletion(): >> Block completed: 1/6
checkCompletion(): >> Block completed: 2/6
checkCompletion(): >> Block completed: 3/6
checkCompletion(): >> Block completed: 4/6
checkCompletion(): >> Block completed: 5/6

In this case only one runAction failed to completed, in other case 2, 3 or none.

I really don't understand where the problem come from.

UPDATE

In some cases the app crashed with EXC_BAD_ACCESS on main thread. This seems to be related to SKCSprite::update(double):

来源:https://stackoverflow.com/questions/30683897/runaction-on-sknode-does-not-complete

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!