delegate / protocol not receiving messages, help!

macOS - I'm subclassing AVPlayerView to create my own keyDown functionality... I need to get the keyDown data from my AVPlayerView subclass to my viewController. Using delegate / protocol (although seriously thinking of abandoning it for NSNotification or something else). Here's what I have so far:

Code Block
class ViewController: NSViewController, ReceiveKeyDownData {
var customPlayerView: CustomAVPlayerView?
override func viewDidLoad()
{
    super.viewDidLoad()
customPlayerView?.keyboardDelegate = self
}
func receiveKeyboardData(data: UInt16) {
    print("from VC: \(data)") //this does not work!
   }
}
protocol ReceiveKeyDownData: class
{
  func receiveKeyboardData(data: UInt16)
}
class CustomAVPlayerView : AVPlayerView
{
   
  weak var keyboardDelegate: ReceiveKeyDownData?
   
  override var acceptsFirstResponder: Bool {
      get {
        return true
      }
    }
   
  override func keyDown(with event: NSEvent) {
    if self.superview != nil
    {
      print("from PlayerView: \(event.keyCode)") // this works!
      self.keyboardDelegate?.receiveKeyboardData(data: event.keyCode)
    }
   }
   
}

This follows the pattern I have seen in many internet delegate / protocol tutorials. I suspect that perhaps when I'm saying "var customPlayerView: CustomAVPlayerView?" that I'm instantiating ANOTHER PlayerView, not the one I already have. ??? Or, there is something about it being optional? For example, if I change the var to let, I get an error saying I have no initializers. I have tried creating initializers, and I'm just LOST. I don't even know what I'm trying to initialize... the delegate? It leads down this path of "required inits" and super.inits and it's just an unholy mess. Super frustrating. Guidance?


Replies

I'm instantiating ANOTHER PlayerView, not the one I already have. 

NO, there is no code instantiating CustomAVPlayerView.

Or, there is something about it being optional?

Maybe. Please try inserting print(customPlayerView) between line 7 and 8, and tell us what you see.


It does not print anything. I tried changing it to...
Code Block
var customPlayerView = CustomAVPlayerView()
override func viewDidLoad() {
    super.viewDidLoad()
print(customPlayerView)
    customPlayerView.keyboardDelegate = self
}

also prints nothing. But how is "var customPlayerView = CustomAVPlayerView()" not instantiating the class?



also prints nothing.

Then, viewDidLoad of your ViewController is not called. Which means your ViewController is not shown in any of the windows of your app.
How have you set up your project and storyboard?
Hmm. You are right that viewDidLoad() is not being called. I don't know why. I did change the identity / class of my playerView to my customAVPlayerView class ... but the View Controller still has the class of "ViewController." I don't know how I can show you my storyboard... I don't see an add photo function here.
Old macOS apps did not use view controllers, so if you touched your project based on some old documents or tutorials, a window may open without view controllers, even if Custom Class of View Controller is set to ViewController in the storyboard.

Please find what is wrong, until then, I cannot say anything sure.
I just created the project the normal way... xcode 12.3 on catalina 10.15.7. I just opened another app I made the other day and the view does load there. The only thing I can think of is that I have two classes in the same file. My ViewController swift file has a View Controller class, and I'm also subclassing AVPlayerView in the same file, as my code shows. I don't know if that's the right or wrong way to do it. I'm not using any old tutorials.

The only thing I can think of is that I have two classes in the same file. My ViewController swift file has a View Controller class, and I'm also subclassing AVPlayerView in the same file, as my code shows. I don't know if that's the right or wrong way to do it. I'm not using any old tutorials. 

That may not prevent ViewController to work, when other settings are normal.

that viewDidLoad() is not being called.

How have you confirmed that?
I just removed the code that subclassed AVPlayerView, and set the identity inspector back to nothing. Now my view IS loading. So it's definitely the fact that I'm subclassing AVPlayerView.

I moved all the subclassing code to another file. Now when I ask in viewDidLoad to print(customPlayerView) I get...

<Player01.CustomAVPlayerView: 0x10100ee00>

!!! We're getting close !!!

print(customPlayerView.keyboardDelegate) is also printing Optional(<Player01.ViewController: 0x100631bf0>), so that seems to be instantiated at least.

However... data is still not being passed to my delegate function in VC. I inserted this line in my keyDown function...

Code Block
print("from CPV: \(self.keyboardDelegate as Any)")

and it is printing nil. So even though my class is being instantiated, and the delegate set on the VC side... do I have to init the delegate in my custom class?
This code:

Code Block
var customPlayerView = CustomAVPlayerView()
and this description:

 I did change the identity / class of my playerView to my customAVPlayerView class

are inconsistent.

When you set Custom Class on the storyboard, it is NOT you who instantiate the view controller or the view. iOS instantiates it.

Do you remember you wrote this?

I'm instantiating ANOTHER PlayerView, not the one I already have.

With writing CustomAVPlayerView(), you ARE instantiating ANOTHER CustomAVPlayerView.


You need to declare an @IBOutlet to receive the right instance which iOS created for you.
Code Block
@IBOutlet weak var customPlayerView: CustomAVPlayerView!


If you have set up your storyboard correctly, you can connect your CustomAVPlayerView on the storyboard to the outlet declared above.
AH! Okay, problem solved! I still had the old IBOutlet from the original AVPlayerView before I subclassed it. So now I have removed that link, and instead hooked up my customAVPlayerView, and using that as the reference I am able to pass data (via protocol / delegate) to my VC. THANK YOU!!!!

I somehow missed the chapter on all the ways one can pass data between two classes. I kind of find the protocol / delegate thing to be a bit of a PITA. Maybe there are better and easier ways to do this?

Thank you again!