Search code examples
swiftmacosnssplitviewcontroller

NSSplitViewController does not call delegate methods


I'm using an NSSplitViewController subclass and the delegate methods are not being called.

This is purely programmatically without nib/storyboard.

The code can be copied to a new project. The file needs to be named main.swift. Also remove "Main interface" in the project settings.

// File: main.swift

import Cocoa

// AppDelegate

class AppDelegate: NSObject, NSApplicationDelegate {

  let window = NSWindow(
    contentRect: NSRect(x: 0, y: 0, width: 600, height: 400),
    styleMask: [ .titled, .closable, .resizable ],
    backing: .buffered,
    defer: false
  )

  func applicationDidFinishLaunching(_ aNotification: Notification) {
    let splitViewController = MySplitViewController()
    window.contentView = splitViewController.view
    window.makeKeyAndOrderFront(nil)
  }

}

// NSSplitViewController

class MySplitViewController: NSSplitViewController {

  convenience init() {
    self.init(nibName: nil, bundle: nil)
    // Left
    let viewController1 = NSViewController()
    viewController1.view = NSView()
    let item1 = NSSplitViewItem(viewController: viewController1)
    item1.minimumThickness = 100
    item1.maximumThickness = 200
    addSplitViewItem(item1)
    // Right
    let viewController2 = NSViewController()
    viewController2.view = NSView()
    let item2 = NSSplitViewItem(viewController: viewController2)
    addSplitViewItem(item2)
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    print(splitView.delegate!)   // Logs "Project1.MySplitViewController"
  }

  // Never called
  override func splitView(_ splitView: NSSplitView, additionalEffectiveRectOfDividerAt dividerIndex: Int) -> NSRect {
    print("\(#function)")
    return super.splitView(splitView, additionalEffectiveRectOfDividerAt: dividerIndex)
  }

}

let application = NSApplication.shared
let applicationDelegate = AppDelegate()

application.delegate = applicationDelegate
application.run()

When running the code you can see that the split view shows up and works fine.

The viewDidLoad() method prints "Project1.MySplitViewController", so the delegate is set.

But the splitView(_:additionalEffectiveRectOfDividerAt:) method is not called (or any other NSSplitViewDelegate if implemented).


Solution

  • The delegate method is not called because the MySplitViewController is released at the end of applicationDidFinishLaunching. Let AppDelegate hold a strong reference to the MySplitViewController.