swiftxcodeswift-playgroundnstouchbar

Implement TouchBar functionality in Xcode Playgrounds


How can I implement a NSTouchBar in using only Xcode Playgrounds? I realize that NSTouchBar, and its accompanying methods including makeTouchBar() are contained within the NSResponder class, which is the superclass of NSView, NSViewController, NSWindow, and SKView (a subclass of NSView.)

It is for this reason that I'm a little unsure how to approach access the TouchBar. There are so many subclasses of NSResponder I'm unsure as to which one is the correct one. And to my knowledge I cannot even access all of them, including the NSWindow for the Playground, which I suspect may be the one I need to access.

My current setup is:

let containerView = SKView()
PlaygroundPage.current.liveView = containerView
let containterScene = SKScene()
containerView.presentScene(containterScene)

And in checking the responder chain, for the SKView I get:

<SKScene> name:'(null)' frame:{{-250, -250}, {500, 500}} anchor:{0.5, 0.5}

And for the SKScene:

<SKView: 0x7fba36037a00>
<NSView: 0x7fba32d6fe80>
<PlaygroundViewBridgeService: 0x7fba32d569e0>
<NSNextStepFrame: 0x7fba32d76e20>
<NSWindow: 0x7fba32e177e0>

For some reason, the SKScene and SKView are not within the same chain, and I can't seem to access any responder higher than the SKView. Is there a way to extend the functionality of the already existing NSWindow?

Another problem is that many tutorials on using the TouchBar require access to the AppDelegate, which I don't think I have in Xcode Storyboards.

Any help implementing the TouchBar in Storyboards would be greatly appreciated.


Solution

  • The solution is actually quite simple. Create a custom subclass of NSViewController and implement the TouchBar override functions within it.

    Then implement the above code:

    let containerView = CustomSKView()
    let containterScene = CustomSKScene()
    containerView.presentScene(containerScene)
    

    With the following additions.

    let containerViewController = CustomNSViewController()
    containerViewController.view = containerView
    PlaygroundPage.current.liveView = containerViewController.view
    

    This sets your custom NSViewController within the responder chain, allowing it to take care of the Touch Bar. There is also no need to worry about the App Delegate.