ioscallbackgrand-central-dispatchcadisplaylink

Is CADisplayLink callback always runs on the main thread?


I couldn't find any direct answer online nor within the docs about this. If I'm setting up CADisplayLink with the following:

 let displayLink = CADisplayLink(target: self, selector: #selector(updateShimmer))
 displayLink.add(to: .current, forMode: .common)

@objc func updateShimmer() {
   print(Thread.isMainThread)
}

I'm getting true. I know that I can wrap this within a DispatchQueue.main but I was wondering, is it always dispatched on the main queue? Or should I wrap it anyway?


Solution

  • You do not need to manually dispatch code inside your display link handler to the main thread. Timers and display links added to a particular run loop will always run on the thread associated with that run loop. For more information, see Threading Programming Guide: Run Loops.

    Bottom line, if you add(to:forMode:) to the main run loop, the main run loop always runs on the main thread.

    That having been said, if you want to make sure it always runs on the main thread, I would suggest being explicit and adding it to .main, not just .current. That removes any ambiguity:

    let displayLink = CADisplayLink(target: self, selector: #selector(updateShimmer(_:)))
    displayLink.add(to: .main, forMode: .common)
    

    Note, I also tweaked the signature of updateShimmer to accept a parameter. The display link will be passed to it. It’s often useful to have that reference inside the method. And, regardless, it makes one's code more self-evident: You can just glance at this method now and understand that this is a display link handler:

    @objc func updateShimmer(_ displayLink: CADisplayLink) {
         ...
    }