快速关闭中的Int不会递增

时间:2014-07-28 18:05:04

标签: swift closures

我在下面的代码中有一个闭包,它在一组自定义SKShapeNodes(blockNode)上执行。我遇到的问题是completedActionsCount始终为1,无论执行闭包多少次。是completedActionsCount只是在关闭开始时被复制了吗?我在这里找不到什么东西?

for action in blockActionSets[index]
        {
            var blockActionSet = blockActionSets[index]

            var completedActionsCount = 0

            let blockNode = getBlockNodeForBlock(action.block)

            if blockNode
            {
                blockNode!.updateWithAction(action, completion:
                    { blockAction in

                        completedActionsCount++

                        println(completedActionsCount)
                        println(blockActionSet.count)
                        if (completedActionsCount == blockActionSet.count)
                        {
                            index = index + 1
                            self.executeBlockActionSetAtIndexRecursive(index, blockActionSets: blockActionSets, completion: completion)
                        }
                    })
            }
            else
            {
                completedActionsCount++
            }
        }

以下代码是块的执行方式:

func updateWithAction(blockAction : BlockAction, completion : (BlockAction) -> Void)
{
    if blockAction.blockActionType == BlockActionType.ChangeColor
    {
        var startColor = CIColor(CGColor: self.fillColor.CGColor)
        var endColor = CIColor(CGColor: UI.getUIColorForBlockType(blockAction.endBlockType).CGColor)

        var startRed = startColor.red()
        var startGreen = startColor.green()
        var startBlue = startColor.blue()
        var endRed = endColor.red()
        var endGreen = endColor.green()
        var endBlue = endColor.blue()

        var action = SKAction.customActionWithDuration(CHANGE_COLOR_ANIMATION_DURATION, actionBlock: {(node : SKNode!, elapsedTime : CGFloat)->Void in
                var blockNode = node as? BlockNode

                if blockNode
                {
                    var ratio : CGFloat = min(1.0, elapsedTime / CGFloat(self.CHANGE_COLOR_ANIMATION_DURATION))

                    blockNode!.fillColor = UIColor(red: startRed + ratio * (endRed - startRed),
                        green: startGreen + ratio * (endGreen - startGreen),
                        blue: startBlue + ratio * (endBlue - startBlue),
                        alpha: 1.0)
                }

                if elapsedTime >= CGFloat(self.CHANGE_COLOR_ANIMATION_DURATION)
                {
                    completion(blockAction)
                }
            })

        self.runAction(action)
    }
}

1 个答案:

答案 0 :(得分:2)

我认为问题是你在循环中定义了completedActionsCount变量,所以每次循环时都会定义一个新的Int值,值为重置为0

这对你有用吗?

var completedActionsCount = 0

for action in blockActionSets[index] {
    var blockActionSet = blockActionSets[index]

    …
}

重新阅读问题...我不确定你是否打算让每个blockActionSet拥有它自己的计数器。但是,为了回答你的一个子问题,我很确定即使Int是一个值类型,它也没有被复制到闭包中,它可以通过外部作用域获得,而你应该能够修改它。

updateWithAction:completion:是否在当前线程中运行?如果它是异步的,那可能是一个因素。

对更新的响应:通常,名称中包含“withDuration”的任何API都是异步的,以避免阻塞主线程。

我不确定到底发生了什么,但如果计数器被复制,因为它是一个值类型,我不知道切换到主线程是否会真正解决你的问题,但是值得一试:

blockNode!.updateWithAction(action, completion:
    { blockAction in
        dispatch_async(dispatch_get_main_queue()) {            
            completedActionsCount++
            …
        }
    }
})

我对这种方法的希望有点低,但因为我怀疑该值正在复制并再次复制它肯定不会让你回到原始参考。您可以将引用包装在引用类型(如变量数组或字典)中:

var completedActionsCounts : [Int:Int] = [:]

for action in blockActionSets[index] {
    var blockActionSet = blockActionSets[index]

    completedActionsCounts[index] = 0
    …

    blockNode!.updateWithAction(action, completion:
        { blockAction in
            dispatch_async(dispatch_get_main_queue()) {            
                completedActionsCounts[index] += 1
                …
            }
        }
    })
}