7

Similar to this question, I'm trying to set the first responder to the first of three NSTextFields in a very simple app. The advice there (set the Window's first responder in interface builder) doesn't seem to apply anymore, at least not when Storyboards are involved. The Window object does indeed have an initialFirstResponder outlet, but I can find no way of setting it via drag, ctrl-drag etc., in either direction to/from the NSTextField.

The structure IB has provided me with comprises a Window Controller Scene (itself just an empty window) linked to a View Controller Scene (which in turn contains my set of NSTextFields and labels).

My suspicion is that there's some default assumption/association that Xcode's baked into my app that causes the Window controller to automatically load a particular view at runtime, and that's why it's not possible to bind an initial responder that it doesn't know about at build time. Which then leaves me wondering which lifecycle call on which object is the right point to be calling self.view.window.initialFirstResponder = myTextField before it's too late, and how to most correctly gain access to that object. viewWillAppear or viewDidLoad in the View Controller feel right, but neither seem to reliably have any effect (the initially active NSTextField varies from run to run, sometimes appearing to track code changes, but either times not).

I've posted the code so far on GitHub

Community
  • 1
  • 1
Chris
  • 3,445
  • 3
  • 22
  • 28

1 Answers1

3

initialFirstResponder is only applied when the NSWindow first appears on the screen. As per the Xcode docs:

`NSWindow initialFirstResponder`
The view that’s made first responder (also called the key view) the first time the window is placed onscreen.

If you want to set something as first responder then you need to invoke:

swift: yourTextField.becomeFirstresponder()

Obj-C: [yourTextField becomeFirstresponder];

Hope the helps!

Ade

edit

I literally shaved your .m down to a few lines:

    #import "ViewController.h"

    @implementation ViewController

    #pragma mark - View lifecycle

    -(void)viewWillAppear{
        [super viewWillAppear];
        //[self.userTextField becomeFirstResponder];
        [self.pathTextField becomeFirstResponder];
    }

    #pragma mark - Connection actions

    - (IBAction)connectClicked:(id)sender {

    }

    - (IBAction)cancelClicked:(id)sender {
        // Tell the app delegate (once we've actually got a pointer to it) that we want to exit
    //    [self.delegate exitApplication];
    }



    @end

My fault! Sorry, viewWillAppear (just before the view actually shows up) is where you put becomeFirstResponder..

Apologies for the mistake!

Adrian Sluyters
  • 2,186
  • 1
  • 16
  • 21
  • Yeh, that's why I was wondering at which point in the app lifecycle it was possible to programmatically set the window's initialFirstResponder - I'm not up to speed on app, window, view and controller lifecycle in a Storyboard world. Also, that's not the right call. From the docs : "Use the NSWindow makeFirstResponder: method, not this method, to make an object the first responder. Never invoke this method directly.". becomeFirstResponder is a method views can implement to refuse becoming firstResponder. Still, makeFirstResponder doesn't work for me either! – Chris Jan 23 '16 at 20:20
  • personally I either invoke it on init or viewDidLoad:. At either which way provided that the control (NSTextField etc..) is bound to an @IBOutlet properly, then you can easily call self.whateverControl.becoemFirstRsponder() at the init() stage or viewDidLoad() stage.. Either of which happen WAY before the view heir achy actually takes effect. – Adrian Sluyters Jan 23 '16 at 20:23
  • makeFirstResponder returns NO for me from viewDidLoad – Chris Jan 23 '16 at 20:32
  • In the viewDidLoad query: myControl.refusesFirstResponder (boolean value)... This is settable in IB. It's about 2/3 the way down the Attributes Inspector of the control... – Adrian Sluyters Jan 23 '16 at 20:34
  • prior to querying it, if it is set to "false" / "NO" then [myControl setRefusesFirstResponder: NO]; or myControl.refusesFirstreponder = false – Adrian Sluyters Jan 23 '16 at 20:36
  • refuseFirstResponder is un-checked in the IB inspector for all fields – Chris Jan 23 '16 at 20:37
  • can you post it on Github and share the link? – Adrian Sluyters Jan 23 '16 at 20:37
  • Let us know :) It's probably one of the annoying quirks that Xcode exhibits by foraging away things in "impossible to find" areas... :-/ – Adrian Sluyters Jan 23 '16 at 20:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101487/discussion-between-chris-and-adrian-sluyters). – Chris Jan 23 '16 at 20:50
  • 3
    Unfortunately, that's not the solution. `becomeFirstResponder` is for asking a view if it is willing to be firstResponder (and as per the docs, not for us to call anyway), not for setting it as firstResponder. In my experience, the actual firstResponder is semi-random. It may look right, and it may not change for several runs/builds, but a clean and rebuild is likely to cause it to change (even with no code change). – Chris Jan 23 '16 at 21:36
  • [Docs](https://developer.apple.com/documentation/appkit/nsresponder/1526750-becomefirstresponder?language=objc): Use the NSWindow [`makeFirstResponder:`](https://developer.apple.com/documentation/appkit/nswindow/1419366-makefirstresponder?language=objc) method, not this method, to make an object the first responder. Never invoke this method directly. – Dimitar Nestorov Apr 06 '20 at 06:44