Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No way to pass new argument to `init` for `NSView`

In the following code, I'm trying to pass an additional argument to VidePlayerView. Right now, I'm creating an instance of VideoPlayerView and I'm passing no arguments to it. However, this ends up calling the init methods with an NSRect arguments (which I don't really know where that comes from).

I want to pass an additional argument to VideoPlayerView, but I have no idea how to do this since it seems that I don't have access to the frame argument.

import SwiftUI
import AVKit

// Note: I couldn't find a way to pass this through the `init` method
var playerLayer = AVCaptureVideoPreviewLayer()

final class VideoPlayerView: NSView {

    // MARK: - Initializers
    override public init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        commonInit()
    }

    required public init?(coder decoder: NSCoder) {
        super.init(coder: decoder)
        commonInit()
    }

    private func commonInit() {
        // Do something with playerLayer
    }
}

public struct VideoPlayerViewView: NSViewRepresentable {

    init(layer: AVCaptureVideoPreviewLayer?) {
        if let layer = layer {
            playerLayer = layer
        } else {
            print("No Layer Set")
        }

    }

    public func makeNSView(context: NSViewRepresentableContext<VideoPlayerViewView>) -> NSView {
        return VideoPlayerView()
    }
}

Currently, I'm solving this problem by ignoring the frame argument, but not sure if that is important.

final class VideoPlayerView: NSView {

    private var playerLayer = AVCaptureVideoPreviewLayer()
    private let rootLayer = CALayer()

    // MARK: - Initializers
    override public init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        commonInit()
    }

    public init(layer: AVCaptureVideoPreviewLayer) {
        self.playerLayer = layer
        super.init(frame: NSRect())
        commonInit()
    }
...
 public func makeNSView(context: NSViewRepresentableContext<VideoPlayerViewView>) -> NSView {
        return VideoPlayerView(layer: self.playerLayer)
    }
like image 390
Jorge Silva Avatar asked Oct 22 '25 16:10

Jorge Silva


1 Answers

Here is possible approach. Tested with Xcode 11.4

final class VideoPlayerView: NSView {
    private var playerLayer: AVCaptureVideoPreviewLayer?

    // MARK: - Initializers
    override public init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        commonInit()
    }

    public convenience init(frame frameRect: NSRect = .zero, layer: AVCaptureVideoPreviewLayer?) {
        self.init(frame: frameRect)
        self.playerLayer = layer
    }

    required public init?(coder decoder: NSCoder) {
        super.init(coder: decoder)
        commonInit()
    }

    private func commonInit() {
        // Do something with playerLayer
    }
}

public struct VideoPlayerViewView: NSViewRepresentable {

    init(layer: AVCaptureVideoPreviewLayer?) {
        if let layer = layer {
            playerLayer = layer
        } else {
            print("No Layer Set")
        }

    }

    public func makeNSView(context: NSViewRepresentableContext<VideoPlayerViewView>) -> NSView {
        return VideoPlayerView(layer: playerLayer)
    }

    public func updateNSView(_ nsView: NSView, context: Context) {
    }
}
like image 51
Asperi Avatar answered Oct 25 '25 04:10

Asperi