我有以下功能,并不像我预期的那样。
func dispatchTrouble(startValue:Float, endValue:Float, duration:Float)
{
//100 increment steps per second
let incrementSteps = duration * 100
for(var step = 0.0 as Float; step < incrementSteps; step++)
{
var delayInSeconds = step * (duration / incrementSteps)
let answer = Float(NSEC_PER_SEC) * delayInSeconds
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(answer))
println(step)
//Using GCD to perform this on the main thread.
dispatch_after(popTime, dispatch_get_main_queue()){
println(step)
let fraction = step / incrementSteps
let incrementedValue = startValue + (endValue - startValue) * fraction
println(incrementedValue)
}
}
}
我希望println(incrementedValue)语句显示一个从startValue增加到endValue的值,并以持续时间内传递的秒数结束。
然而,我得到的行为是dispatch_after闭包中的代码只打印最终值,它从不打印增量。
延迟按预期发生,但所有值都计算好像for循环已经完成。第一个println(步骤)显示步骤递增,但第二个只显示最终值。
我显然对这应该如何运作有误解。我预计闭包中的代码将保存调用dispatch_after方法时存在的值,但它的作用就像它使用的是实际执行时的值。
如何在for循环的每次迭代中捕获值并使用它来执行闭包中的代码?
答案 0 :(得分:1)
您发送给GDC的所有闭包都指向相同的step
变量。这意味着每当其中一个执行时,它就具有循环结束时的值。
尝试将代码更改为:
func dispatchTrouble(startValue:Float, endValue:Float, duration:Float)
{
//100 increment steps per second
let incrementSteps = duration * 100
for(var step = 0.0 as Float; step < incrementSteps; step++)
{
var delayInSeconds = step * (duration / incrementSteps)
let answer = Float(NSEC_PER_SEC) * delayInSeconds
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(answer))
println(step)
let stepCopy = step
//Using GCD to perform this on the main thread.
dispatch_after(popTime, dispatch_get_main_queue()){
println(stepCopy)
let fraction = stepCopy / incrementSteps
let incrementedValue = startValue + (endValue - startValue) * fraction
println(incrementedValue)
}
}
}
它会像那样工作。正如the swift reference所述,关闭正在step
上保留。
答案 1 :(得分:1)
与捕获值的Objective-C块不同,Swift闭包捕获变量。这意味着Objective-C块将捕获100个不同的“step”变量值,Swift闭包捕获变量本身并在调用闭包时打印其值。
解决此问题的最佳方法是添加捕获列表。
dispatch_after(popTime, dispatch_get_main_queue()){
[let stepcopy = step] () -> Void in
println(stepcopy)
let fraction = stepcopy / incrementSteps
let incrementedValue = startValue + (endValue - startValue) * fraction
println(incrementedValue)
}
因此,闭包以{开头,后跟[括号]中的捕获列表,后跟可选的(参数) - &gt;结果,然后是代码。
通过使用Float而不是Double,BTW可以将精度降低到大约7位而不是15位,这是没有任何理由的。