I am using a CADisplayLink as a timer in my application. I am using a CADisplayLink because my app relies HEAVILY on the accuracy/precision of the CADisplayLink. NSTimer is not a suitable replacement in my case.
The issue is that occasionally, I need the CADisplayLink to fire and call its selector, while the application is in the background. Is this even possible? I understand that the CADisplayLink is linked to the refresh rate of the application UI. Does this mean that, when my app is in the background, there is no UI, and thus it is impossible to use a CADisplayLink in this case? Or, is it possible to somehow use the CADisplayLink by changing the run loop that I add it to or by changing the forMode
argument? or perhaps using some GCD trickery/work-around?
Note: My app is using an AudioPlayer and thus I have background capabilities enabled. I am able to run other code while in the background. Just to test, I switched my CADisplayLink with an NSTimer, and the NSTimer fired and called its selector as I wanted it to. I just can't get the CADisplayLink to fire and I can't find any definitive documentation regarding the possibility of using it in the background
Here is my current code pertaining to my display link:
func beginTimer(){
dispatch_async(dispatch_get_main_queue()){
self.displayLink = CADisplayLink(target: self, selector: "update")
self.displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
}
}
func update(){
delegate?.executeCallback
}
It makes an undocumented sort of sense that your display link callback is not called in the background, seeing as you shouldn't be drawing anyway (in fact if you do any GPU work in the background your app gets killed).
So if you're already using audio and a background mode why not try implementing your timing by doing your audio with an remoteIO audio unit* and counting output samples instead of screen refreshes?
With this path you can choose an output buffer size equivalent to or smaller than the usual 60Hz screen refresh.
I think you ought to be able get comparable (and maybe better) timing accuracy, although there will be caveats in low power mode / other app interactions where iOS may choose to change your buffer size from underneath you. Some experimentation will be necessary.
*I don't think AVAudioEngine
has an equivalent of this procedural output yet.