Question

Im working on a tiny app just to learn cocoa, and Im having a hard time with setting FirstResponder to some NSTextFields.

When the view opens, I want the first NSTextField, clientNumber, to be selected, so I trigger [clientNumber becomeFirstResponder] at the end of my loadView method, but it does not select the text field. But when I click the button that fires the (IBAction)addToArray method, it selects the right text field. Further do I have another text field, it should contain integers only, so I have a crude verification for it. When the content is not a int, I get a beep, just like it should, but it does not select the text field.

Here is my code:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
      NSLog(@"initWithNibName");
    }
    return self;
}

- (void)viewWillLoad {
    NSLog(@"viewWillLoad");
}

- (void)viewDidLoad {
    NSLog(@"viewDidLoad");
    [self initNewInvoice];    
}

- (void)loadView {
    NSLog(@"loadView");
    [self viewWillLoad];
    [super loadView];
    [self viewDidLoad];
    FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.clientNumber]; 
}

- (void)awakeFromNib
{
    NSLog(@"awakeFromNib");
}

- (IBAction)saveInvoice:(id)sender
{
    FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.invoiceCredit]; 
}

- (IBAction)addToArray:(id)sender
{
    [clientNumber setStringValue: @"Toodeloo"];
    FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.clientNumber];  
}

- (IBAction)updateCreditDays:(id)sender
{
    if(invoiceCredit.intValue){
        [self updateCredit];
    }else{
        NSBeep();
        FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; 
    [appDelegate.window makeFirstResponder:self.invoiceCredit]; 
    }
}

I really hope someone can help me out here.

EDIT:

I got it all wrong, thanks for the pointers, but when I fix the code, using this: FakturaAppDelegate *appDelegate = (FakturaAppDelegate *)[[NSApplication sharedApplication] delegate]; [appDelegate.window makeFirstResponder:self.invoiceCredit]; instead of becomeFirstResponder. But it still doesnt work.

Was it helpful?

Solution

You are making this much harder than it needs to be.

In Interface Builder, set the initialFirstResponder outlet of your window to point to your text field.

That's it.

If you absolutely must do it programmatically, use:

[window setInitialFirstResponder:yourTextField];

Remember, if you're fighting with Cocoa to do something that seems like it should be simple, then you're probably doing it wrong.

OTHER TIPS

Override viewDidAppear, and within said method, call the NSTextField's becomeFirstResponder method.

Note that in my own work, viewWillAppear has proven to be too early for said call, whether using the NSTextField's becomeFirstResponder method or the NSWindow's makeFirstResponder method.

The trouble is that self.view.window is null in the first view controller's viewDidLoad method until after applicationDidFinishLaunching exits. So, becomeFirstResponder doesn't work in viewDidLoad. Try delaying the setting of the first responder, like so:

[_yourTextField performSelector:@selector(becomeFirstResponder) withObject:nil afterDelay:0.1];

You should never try to set first responder in viewDidLoad method because window is still nil at that point. Use viewWillAppear instead:

- (void)viewWillAppear
{
    [super viewWillAppear];
    if (!_started) {
        _started = YES;
        [self.view.window makeFirstResponder:_yourView];
    }
}

Apple also once said that you should never call becomeFirstResponder directly. Use [yourWindow makeFirstResponder:yourView]; instead.

Just read the documentation:

becomeFirstResponder

Notifies the receiver that it’s about to become first responder in its NSWindow.

[...]

Use the NSWindow makeFirstResponder: method, not this method, to make an object the first responder. Never invoke this method directly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top