- 
      
- 
        Save CanTheAlmighty/ee76fbf701a61651fe439fcd6d25f41d to your computer and use it in GitHub Desktop. 
| // | |
| // DisplayLink.swift | |
| // MetalMac | |
| // | |
| // Created by Jose Canepa on 8/18/16. | |
| // Copyright © 2016 Jose Canepa. All rights reserved. | |
| // | |
| import AppKit | |
| /** | |
| Analog to the CADisplayLink in iOS. | |
| */ | |
| class DisplayLink | |
| { | |
| let timer : CVDisplayLink | |
| let source : DispatchSourceUserDataAdd | |
| var callback : Optional<() -> ()> = nil | |
| var running : Bool { return CVDisplayLinkIsRunning(timer) } | |
| /** | |
| Creates a new DisplayLink that gets executed on the given queue | |
| - Parameters: | |
| - queue: Queue which will receive the callback calls | |
| */ | |
| init?(onQueue queue: DispatchQueue = DispatchQueue.main) | |
| { | |
| // Source | |
| source = DispatchSource.makeUserDataAddSource(queue: queue) | |
| // Timer | |
| var timerRef : CVDisplayLink? = nil | |
| // Create timer | |
| var successLink = CVDisplayLinkCreateWithActiveCGDisplays(&timerRef) | |
| if let timer = timerRef | |
| { | |
| // Set Output | |
| successLink = CVDisplayLinkSetOutputCallback(timer, | |
| { | |
| (timer : CVDisplayLink, currentTime : UnsafePointer<CVTimeStamp>, outputTime : UnsafePointer<CVTimeStamp>, _ : CVOptionFlags, _ : UnsafeMutablePointer<CVOptionFlags>, sourceUnsafeRaw : UnsafeMutableRawPointer?) -> CVReturn in | |
| // Un-opaque the source | |
| if let sourceUnsafeRaw = sourceUnsafeRaw | |
| { | |
| // Update the value of the source, thus, triggering a handle call on the timer | |
| let sourceUnmanaged = Unmanaged<DispatchSourceUserDataAdd>.fromOpaque(sourceUnsafeRaw) | |
| sourceUnmanaged.takeUnretainedValue().add(data: 1) | |
| } | |
| return kCVReturnSuccess | |
| }, Unmanaged.passUnretained(source).toOpaque()) | |
| guard successLink == kCVReturnSuccess else | |
| { | |
| NSLog("Failed to create timer with active display") | |
| return nil | |
| } | |
| // Connect to display | |
| successLink = CVDisplayLinkSetCurrentCGDisplay(timer, CGMainDisplayID()) | |
| guard successLink == kCVReturnSuccess else | |
| { | |
| NSLog("Failed to connect to display") | |
| return nil | |
| } | |
| self.timer = timer | |
| } | |
| else | |
| { | |
| NSLog("Failed to create timer with active display") | |
| return nil | |
| } | |
| // Timer setup | |
| source.setEventHandler(handler: | |
| { | |
| [weak self] in self?.callback?() | |
| }) | |
| } | |
| /// Starts the timer | |
| func start() | |
| { | |
| guard !running else { return } | |
| CVDisplayLinkStart(timer) | |
| source.resume() | |
| } | |
| /// Cancels the timer, can be restarted aftewards | |
| func cancel() | |
| { | |
| guard running else { return } | |
| CVDisplayLinkStop(timer) | |
| source.cancel() | |
| } | |
| deinit | |
| { | |
| if running | |
| { | |
| cancel() | |
| } | |
| } | |
| } | 
Thanks for sharing! ❤️
I believe you want source.suspend() if you want to be able to restart the timer.
And they say swift is easy and requires fewer lines of code than objc... I setup a DisplayLink in about 5 lines of code in ObJC.
Swift is for people who love writing complicated code
This is based on the implementation done by Apple for MetalBasic3D example: https://developer.apple.com/library/ios/samplecode/MetalBasic3D/Introduction/Intro.html
I took that code and rewrote it in swift and moved into its own class, for easier integration when using Metal.
The Code example you're referring to isn't using a DisplayLink
Note that since mac 10.11 there's CVDisplayLinkSetOutputHandler which makes setting up of the callback simpler.
And they say swift is easy and requires fewer lines of code than objc... I setup a DisplayLink in about 5 lines of code in ObJC.
Swift is for people who love writing complicated code
This is for the Mac though. CADisplayLink for iOS is easy in either Swift or ObjC.
@CanTheAlmighty Thanks your code :)
Can I use your code in my commercial app?
Please let me know how I can use the code for commercial distribution.
This is based on the implementation done by Apple for MetalBasic3D example: https://developer.apple.com/library/ios/samplecode/MetalBasic3D/Introduction/Intro.html
I took that code and rewrote it in swift and moved into its own class, for easier integration when using Metal.