Search code examples
iosmacosswiftuicamera

Problems using AVCaptureVideoPreviewLayer in MacOS


I've been trying to follow a tutorial on embedding an AVCaptureVideoPreviewLayer (or in simpler terms a very basic viewfinder using camera) and have had trouble converting the iOS code to fit my MacOS application.

The issue appeared when I attempted to convert this block of code:

// setting view for preview...

struct CameraPreview: UIViewRepresentable {
    
    @ObservedObject var camera : CameraModel
    
    func makeUIView(context: Context) ->  UIView {
     
        let view = UIView(frame: UIScreen.main.bounds)
        
        camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
        camera.preview.frame = view.frame
        
        // Your Own Properties...
        camera.preview.videoGravity = .resizeAspectFill
        view.layer.addSublayer(camera.preview)
        
        // starting session
        camera.session.startRunning()
        
        return view
    }
    
    func updateUIView(_ uiView: UIView, context: Context) {
        
    }
}

My understanding is that UIViews are only for iOS development and that MacOS uses NSViews instead. Knowing this I did my best to come up with the following modified code

// setting view for preview...

struct CameraPreview: NSViewRepresentable {  // ERROR #1
    
    @ObservedObject var camera : CameraModel
    
    func makeNSView(context: Context) ->  NSView {
     
        let view = NSView(frame: CGRect(origin: .zero,
                                        size: CGSize(width: 200, height: 200)))
        
        camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
        camera.preview.frame = view.frame
        
        // Your Own Properties...
        camera.preview.videoGravity = .resizeAspectFill
        view.addSubview(camera.preview)   //ERROR #2
        
        // starting session
        camera.session.startRunning()
        
        return view
    }
    
    func updateUIView(_ uiView: NSView, context: NSView) {
        
    }
}

The issues are:

  1. Type 'CameraPreview' does not conform to protocol 'NSViewRepresentable' (ERROR #1)
  2. Cannot convert value of type 'AVCaptureVideoPreviewLayer' to expected argument type 'NSView' (ERROR #2)

I'm an intermediate iOS developer, but have been trying to build my skills in MacOS development.


Solution

  • You forgot to update this part updateUIView

        func updateNSView(_ uiView: NSView, context: Context) {    // << here !!
            
        }
    

    about second... you try to add layer to view, but layout should be added to layer, like

        let view = NSView(frame: CGRect(origin: .zero,
                                        size: CGSize(width: 200, height: 200)))
    
        view.wantsLayer = true   // needed explicitly for NSView
    
        ...
    
        view.layer.addSublayer(camera.preview)