I have the following function that doesn't behave as I would have expected.
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)
}
}
}
I expected the println(incrementedValue) statement to display a value that incremented from startValue to endValue and to finish in the number of seconds passed in duration.
However the behavior I get is that the code in the dispatch_after closure only prints the final value, it never prints the increments.
The delay occurs as expected, but the values are all calculated as if the for-loop had already completed. The first println(step) does show step incrementing, but the second one only shows the final value.
I clearly have a misunderstanding of how this should work. I expected that the code in the closure would hold the values that existed at the time the dispatch_after method was called, but it acts like it uses whatever the value is at the time it actually executes instead.
How can I capture the values at each iteration of the for-loop and execute the code in the closure using that?
All the closures you send to GDC are pointing to the same step variable. That means that every time one of them executes, it has the value it had when the loop ended.
Try changing your code to this:
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)
}
}
}
It'll work like that. The closure is doing a retain on step, as explained on the swift reference.
Unlike Objective-C blocks which capture values, Swift closures capture variables. That means where an Objective-C block would have captured 100 different values of the "step" variable, the Swift closure captures the variable itself and prints its value at the time the closure is called.
The best way to fix this is to add a capture list.
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)
}
So a closure starts with {, followed optionally by the capture list in [ brackets], followed optionally by (arguments) -> result in, followed by the code.
BTW by using Float instead of Double you reduce the precision to about 7 digits instead of 15, for no good reason whatsoever.
Related
Why is there a difference between a progress of 0.2 and 0.20? I'm really missing something here.
I have a dynamic total count of data and each data has a page.
let totalDataCount = 5
self.progressView.progress = Float(1/self.totalDataCount) // quotient: 0.2```
While if I set 0.20, I have this:
self.progressView.progress = 0.20
The division 1/5 returns 0 as a result because 1 is type of Int and the result is also Int. Try to change the 1/self.totalDataCount to 1.0/self.totalDataCount and it will work
I have two conditional statement ,
for example ,
if(x<1&&y>6)
{
//get the total time(second) inside this conditional statement
}
if(x<20&&y>30)
{
//get the total time(second) inside this conditional statement
}
My question is,
is it possible use Millis () function to calculate the total time in each "if condition"??
or any other method to calculate time?
please give me some code examples.
Thanks
I have did it according to my understanding if there is something else you were trying to do tell me i will change it accordingly.
uint32_t sec1, sec2;
uint32_t sec = millis()/1000;
if(x<1&&y>6) {
//get the total time(second) inside this conditional statement
//Adding time for summing up the seconds
sec1 = sec1 + (millis() / 1000) - sec;
}
if(x<20&&y>30) {
//get the total time(second) inside this conditional statement
//Adding time for summing up the seconds
sec2 = sec2 + (millis() / 1000) - sec;
}
In my app, I give the user the option to play a small frame of audio (from a larger audio file)in order to listen over and over to do a manual transcription. AKPlayer makes this trivial. Now, because the frame of audio is pretty small, it's pretty intense to hear this loop over and over (a little maddening in the classical sense of the word). I'd like to either fade it out/fade it back in with the loop OR just inject like 500 ms of silence before the loop starts again. I have no idea where to start, here is the current working code as is:
public func playLoop(start: Double, end: Double) {
self.chordLoopPlayer.isLooping = true
self.chordLoopPlayer.buffering = .always
self.chordLoopPlayer.preroll()
let millisecondsPerSample : Double = 1000 / 44100
let startingDuration : Double = (((start * millisecondsPerSample) / 1000) / 2)
let endingDuration : Double = (((end * millisecondsPerSample) / 1000) / 2)
print("StartinDuration:\(startingDuration) | EndingDuration:\(endingDuration)")
self.chordLoopPlayer.loop.start = startingDuration
self.chordLoopPlayer.loop.end = endingDuration
self.chordLoopPlayer.play(from: startingDuration, to: endingDuration)
Thanks so much <3
You just need to set .fade values for your fade-in/fade-out prior to calling the play() function. AudioKit will execute them each time going in and out of the loop. So assuming you'd like a 2-second fade-out, and a 2-second fade-in (adjust to your taste), your code would look like:
public func playLoop(start: Double, end: Double) {
self.chordLoopPlayer.isLooping = true
self.chordLoopPlayer.buffering = .always
self.chordLoopPlayer.preroll()
let millisecondsPerSample : Double = 1000 / 44100
let startingDuration : Double = (((start * millisecondsPerSample) / 1000) / 2)
let endingDuration : Double = (((end * millisecondsPerSample) / 1000) / 2)
print("StartinDuration:\(startingDuration) | EndingDuration:\(endingDuration)")
self.chordLoopPlayer.loop.start = startingDuration
self.chordLoopPlayer.loop.end = endingDuration
// add fade in/out values to fade in or fade out during playback; reset to 0 to disable.
self.chordLoopPlayer.fade.inTime = 2 // in seconds
self.chordLoopPlayer.fade.outTime = 2 // in seconds
self.chordLoopPlayer.play(from: startingDuration, to: endingDuration)
}
I find the AudioKit documentation a bit frustrating in this respect, as it's not super-easy to find these properties if you don't already know what you're looking for, or to understand how to use them if you haven't already come across sample code, so I hope this is a useful example for others who happen to search on this topic on SO. In any case, the list of sub-properties associated with AudioKit's .fade property is here: https://audiokit.io/docs/Classes/AKPlayer/Fade.html
I have the following custom SKAction working but as an EaseIn instead EaseOut. I want it to EaseOut! I have failed miserably to correct it using various easing equations found around the web.
let duration = 2.0
let initialX = cameraNode.position.x
let customEaseOut = SKAction.customActionWithDuration(duration, actionBlock: {node, elapsedTime in
let t = Double(elapsedTime)/duration
let b = Double(initialX)
let c = Double(targetPoint.x)
let p = t*t*t*t*t
let l = b*(1-p) + c*p
node.position.x = CGFloat(l)
})
cameraNode.runAction(customEaseOut)
Any help would be much appreciate.
Thanks
You don't need to calculate it.
SKAction just have a property called timingMode:
// fall is an SKAction
fall.timingMode = .easeInEaseOut
You can choose from:
linear (default)
easeIn
easeOut
easeInEaseOut
Check details from API docs and also here.
If you need to change the Apple presets you can use: timingFunction
fall.timingFunction = { time -> Float in
return time
}
To build a custom function according to the source:
/**
A custom timing function for SKActions. Input time will be linear 0.0-1.0
over the duration of the action. Return values must be 0.0-1.0 and increasing
and the function must return 1.0 when the input time reaches 1.0.
*/
public typealias SKActionTimingFunction = (Float) -> Float
So with these informations you can write:
func CubicEaseOut(_ t:Float)->Float
{
let f:Float = (t - 1);
return f * f * f + 1;
}
fall.timingFunction = CubicEaseOut
We can modify the following code to allow the custom action to ease-out instead of ease-in
let t = Double(elapsedTime)/duration
...
let p = t*t*t*t*t
To get a better understanding of p, it is helpful to plot it as a function of t
Clearly, the function eases in over time. Changing the definition of t to
let t = 1 - Double(elapsedTime)/duration
and plotting p gives
The action now eases out, but it starts at 1 and ends at 0. To resolve this, change the definition of p to
let p = 1-t*t*t*t*t
I am trying to write this in Swift (I am in step 54). In a UICollectionViewLayout class I have a function setup function
func setup() {
var percentage = 0.0
for i in 0...RotationCount - 1 {
var newPercentage = 0.0
do {
newPercentage = Double((arc4random() % 220) - 110) * 0.0001
println(newPercentage)
} while (fabs(percentage - newPercentage) < 0.006)
percentage = newPercentage
var angle = 2 * M_PI * (1 + percentage)
var transform = CATransform3DMakeRotation(CGFloat(angle), 0, 0, 1)
rotations.append(transform)
}
}
Here is how the setup function is described in the tutorial
First we create a temporary mutable array that we add objects to. Then
we run through our loop, creating a rotation each time. We create a
random percentage between -1.1% and 1.1% and then use that to create a
tweaked CATransform3D. I geeked out a bit and added some logic to
ensure that the percentage of rotation we randomly generate is a least
0.6% different than the one generated beforehand. This ensures that photos in a stack don't have the misfortune of all being rotated the
same way. Once we have our transform, we add it to the temporary array
by wrapping it in an NSValue and then rinse and repeat. After all 32
rotations are added we set our private array property. Now we just
need to put it to use.
When I run the app, I get a run time error in the while (fabs(percentage - newPercentage) < 0.006) line.
the setup function is called in prepareLayout()
override func prepareLayout() {
super.prepareLayout()
setup()
...
}
Without the do..while loop, the app runs fine. So I am wondering, why?
Turns out I had to be more type safe
newPercentage = Double(Int((arc4random() % 220)) - 110) * 0.0001
This must be a Swift bug. That code should NOT crash at runtime. It should either give a compiler error on the newPercentage = expression or it should correctly promote the types as C does.