title: How do I update a CALayer with a CVPixelBuffer/IOSurface?
body: <p>I have an IOSurface-backed CVPixelBuffer that is getting updated from an outside source at 30fps. I want to render a preview of the image data in an NSView -- what's the best way for me to do that?</p>
  <p>I can directly set the .contents of a CALayer on the view, but that only updates the first time my view updates (or if, say, I resize the view). I've been poring over the docs but I can't figure out the correct invocation of needsDisplay on the layer or view to let the view infrastructure know to refresh itself, especially when updates are coming from outside the view.</p>
  <p>Ideally I'd just bind the IOSurface to my layer and any changes I make to it would be propagated, but I'm not sure if that's possible.</p>
  <pre><code>class VideoPreviewController: NSViewController, VideoFeedConsumer {
      let customLayer : CALayer = CALayer()
      
      override func viewDidLoad() {
          super.viewDidLoad()
          // Do view setup here.
          print(&quot;Loaded our video preview&quot;)
          
          view.layer?.addSublayer(customLayer)
          customLayer.frame = view.frame
          
          // register our view with the browser service
          VideoFeedBrowser.instance.registerConsumer(self)
      }
      
      override func viewWillDisappear() {
          // deregister our view from the video feed
          VideoFeedBrowser.instance.deregisterConsumer(self)
  
          super.viewWillDisappear()
      }
      
      // This callback gets called at 30fps whenever the pixelbuffer is updated
      @objc func updateFrame(pixelBuffer: CVPixelBuffer) {
  
          guard let surface = CVPixelBufferGetIOSurface(pixelBuffer)?.takeUnretainedValue() else {
              print(&quot;pixelbuffer isn't IOsurface backed! noooooo!&quot;)
              return;
          }
  
          // Try and tell the view to redraw itself with new contents?
          // These methods don't work
          //self.view.setNeedsDisplay(self.view.visibleRect)
          //self.customLayer.setNeedsDisplay()
          self.customLayer.contents = surface
  
      }
      
  }
  </code></pre>
  <p>Here's my attempt of a scaling version that's NSView rather than NSViewController-based, that also doesn't update correctly (or scale correctly for that matter):</p>
  <pre><code>class VideoPreviewThumbnail: NSView, VideoFeedConsumer {
     
  
      required init?(coder decoder: NSCoder) {
          super.init(coder: decoder)
          self.wantsLayer = true
          
          // register our view with the browser service
          VideoFeedBrowser.instance.registerConsumer(self)
      }
      
      override init(frame frameRect: NSRect) {
          super.init(frame: frameRect)
          self.wantsLayer = true
          
          // register our view with the browser service
          VideoFeedBrowser.instance.registerConsumer(self)
      }
      
      deinit{
          VideoFeedBrowser.instance.deregisterConsumer(self)
      }
      
      override func updateLayer() {
          // Do I need to put something here?
          print(&quot;update layer&quot;)
      }
      
      @objc
      func updateFrame(pixelBuffer: CVPixelBuffer) {
          guard let surface = CVPixelBufferGetIOSurface(pixelBuffer)?.takeUnretainedValue() else {
              print(&quot;pixelbuffer isn't IOsurface backed! noooooo!&quot;)
              return;
          }
          self.layer?.contents = surface
          self.layer?.transform = CATransform3DMakeScale(
              self.frame.width / CGFloat(CVPixelBufferGetWidth(pixelBuffer)),
              self.frame.height / CGFloat(CVPixelBufferGetHeight(pixelBuffer)),
              CGFloat(1))
      }
  
  }
  </code></pre>
  <p>What am I missing?</p>