makeFirstResponder does not always fire

856 Views Asked by At

I have an NSSearchField inside a NSToolbar that I am attempting to set makeFirstResponder on but it is working intermittently. At times the NSSearchField will become the first responder without the call to makeFirstResponder and makeFirstResponder is returning true as if it were set successfully. Setting NSWindow.initialFirstResponder has also failed to work.

class ViewController: NSViewController {
    override func viewDidAppear() {
        super.viewDidAppear()
        view.window?.makeFirstResponder(view.window?.windowController?.searchField
    }
}

I have had consistent working results by delaying the code with a timer but this is a less than ideal solution.

class ViewController: NSViewController {
    override func viewDidAppear() {
        super.viewDidAppear()
        Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
            self.view.window?.makeFirstResponder(self.windowController?.searchField)
        }
    }
}
3

There are 3 best solutions below

0
Hamer On BEST ANSWER

I found a blog that led me to find the reason why this was happening. By default in macOS an NSWindow has an isRestorable Boolean value that will recall whatever the last firstResponder was regardless of what is set as an initialFirstResponder or what is set inside viewDidAppear, etc.

1
Dave Weston On

If makeFirstResponder is returning true, then the it likely was made the first responder for at least a short amount of time.

You can use the fact that NSWindow.firstResponder is KVO compliant in order to detect any changes to it with something like the following code in your ViewController class:

    override func viewDidAppear() {
        super.viewDidAppear()

        self.view.window?.addObserver(self, forKeyPath: "firstResponder", options: [.initial, .new], context: nil)
        self.view.window?.makeFirstResponder(self.windowController?.searchField)
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "firstResponder" {
            print("First responder of window: \(object) is \(change?[NSKeyValueChangeKey.newKey])")
        }
    }
0
Paul Stevenson On

I found that calling webView.makeFirstResponder() didn't do anything. But calling view.window?.makeFirstResponder(webView) did.

no idea why. hours of frustration.