Jorge Silva
Jorge Silva

Reputation: 4614

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)
    }

Upvotes: 4

Views: 290

Answers (1)

Asperi
Asperi

Reputation: 257693

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) {
    }
}

Upvotes: 5

Related Questions