How to set CADisplayLink in Swift with weak reference between target and CADisplayLink instance

后端 未结 3 1069
梦如初夏
梦如初夏 2021-01-23 05:26

In Objective-C, we can init CADisplayLink with Proxy Pattern to break strong reference:

WeakProxy *weakProxy = [WeakProxy weakProxyForObject:self];
self.displayL         


        
3条回答
  •  伪装坚强ぢ
    2021-01-23 05:35

    Another solution, this one hides the proxy / objc runtime from its external API. The DisplayLink stays alive for as long as it is referenced by variable. Once the variable goes out of scope or is set to nil, the CADisplayLink is invalidated so that the target can be deinited also.

    import Foundation
    import UIKit
    
    /// DisplayLink provides a block based interface for CADisplayLink.
    /// The CADisplayLink is invalidated upon DisplayLink deinit.
    ///
    /// Usage:
    /// ```
    /// let displayLink = DisplayLink { caDisplayLink in print("Next frame scheduled \(caDisplayLink.targetTimestamp)") }
    /// ```
    ///
    /// Note: Keep a reference to the DisplayLink.
    final class DisplayLink {
        let displayLink: CADisplayLink
    
        init(runloop: RunLoop? = .main, prepareNextFrame: @escaping (CADisplayLink) -> ()) {
            displayLink = CADisplayLink(
                target: DisplayLinkTarget(prepareNextFrame),
                selector: #selector(DisplayLinkTarget.prepareNextFrame))
    
            if let runloop = runloop {
                displayLink.add(to: runloop, forMode: .default)
            }
        }
    
        deinit {
            displayLink.invalidate()
        }
    }
    
    private class DisplayLinkTarget {
        let callback: (CADisplayLink) -> ()
    
        init(_ callback: @escaping (CADisplayLink) -> ()) {
            self.callback = callback
        }
    
        @objc func prepareNextFrame(displaylink: CADisplayLink) {
            callback(displaylink)
        }
    }
    

提交回复
热议问题