2

Currently, i have a delay function as follows:

//Delay function from http://stackoverflow.com/questions/24034544/dispatch-after-gcd-in-swift/24318861#24318861
func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

This code works for what i need, but as soon as the delay gets greater than 13 or so seconds, it seems to glitch out and stop delaying. Does anyone know a solution to this, or even while this is happening?

Here is the code in my use:

var delayTime = Double(1)
    for number in self.gameOrder{
        if number == 0{
            delay(delayTime++){self.greenButton.highlighted = true}
            self.delay(delayTime++){
                self.greenButton.highlighted = false
            }
        }

        else if number == 1{
            delay(delayTime++){self.redButton.highlighted = true}
             self.delay(delayTime++){
                self.redButton.highlighted = false
            }

        }

        else if number == 2{
            delay(delayTime++){self.yellowButton.highlighted = true}
             self.delay(delayTime++){
                self.yellowButton.highlighted = false
            }
        }
        else if number == 3{
            delay(delayTime++){self.blueButton.highlighted = true}
             self.delay(delayTime++){
                self.blueButton.highlighted = false
            }
        }
        println(delayTime)


    }
}

}

Once delayTime gets to 13, the delay starts to play up.

Thanks!

Kerrek SB
  • 428,875
  • 83
  • 813
  • 1,025
JohnnyCash
  • 67
  • 1
  • 5

1 Answers1

1

You didn't say what platform/OS, but if on iOS, this behavior changed from iOS 7 to iOS 8. It would appear to be coalescing the timers (a power saving feature to group similar timer events together to minimize the power consumption).

The solution is to refactor the code either to use a single repeating timer or rather than scheduling all of the dispatch_after calls up front, have each dispatch_after trigger the next dispatch_after in its completion block (thus never having a bunch of dispatch_after calls pending at the same time that it might be coalesced together).

By the way, if using a repeating timer, you might want to use a dispatch source timer rather than a NSTimer, as this not only gives you the ability to specify the desired leeway, but the third parameter of dispatch_source_set_timer lets you specify a value of DISPATCH_TIMER_STRICT which:

Specifies that the system should make a best effort to strictly observe the leeway value specified for the timer via dispatch_source_set_timer(), even if that value is smaller than the default leeway value that would be applied to the timer otherwise. A minimal amount of leeway will be applied to the timer even if this flag is specified.

CAUTION: Use of this flag may override power-saving techniques employed by the system and cause higher power consumption, so it must be used with care and only when absolutely necessary.

In Mac OS X, this can be used to turn off "App Nap" feature (where timers will be more significantly altered in order to maximize battery life), but given the appearance of this timer coalescing in iOS, it might be a useful option here, too.

Rob
  • 371,891
  • 67
  • 713
  • 902