16

I'm trying to understand how to catch a "text changed" event from a text field in my window. I'm used to Java's "action listeners", and can't find anything similar in Objective-C/Cocoa. I searched for quite a while and found the "key value observing" protocol, but the observeValueForKeyPath: method (function?) only triggers when the value of my text field was changed in code (using [textfield setStringValue:...], e.g.), not by typing in it.

How can I "listen" to the value change when a user types in the text field?

jscs
  • 63,694
  • 13
  • 151
  • 195
Eike Cochu
  • 3,249
  • 7
  • 34
  • 57

4 Answers4

36

You can set a delegate for your NSTextField instance and have the delegate implement the following method:

- (void)controlTextDidChange:(NSNotification *)notification {
    // there was a text change in some control
}

Your delegate object can be the application delegate, a window controller, a view controller, or some other object in your application. The delegate can be programatically set via

[myTextField setDelegate:delegateObject];

or, in Interface Builder, via the delegate outlet available in the NSTextField control.

Note that if there are multiple controls hooked to the same delegate then -controlTextDidChange: will be sent for each control, i.e., the same method is called for different controls. If you want different behaviour according to the control where the text has changed, you can use -[NSNotification object] to identify the control that has sent the notification.

For instance, if you have two text fields with corresponding outlets nameField and addressField, and you’ve set the same delegate for both fields, then:

- (void)controlTextDidChange:(NSNotification *)notification {
    // there was a text change in some control
    // [notification object] points to the control that has sent
    // the notification

    if ([notification object] == nameField) {
        // nameField has changed
    }
    else if ([notification object] == addressField) {
        // addressField has changed
    }
}

Alternatively, you could have one delegate for each text field. In this case, there’d be no need to test [notification object].

  • thanks, that was the next thing i was searching for! i thought it was inconvenient to create new classes for every object that needs a delegate – Eike Cochu May 28 '11 at 23:23
  • @Eike Note that Cyprian’s answer is for iOS and uses the wrong method for what you want. `…shouldBeginEditing:` is implemented when you want to control whether the text field should allow editing of text. –  May 28 '11 at 23:42
  • side question: does anyone understand how to _predict_ whether a given event will be available via IB or require the delegate mechanism ? Is it Apple's estimate of how commonly the event will be used, or is it something more formal than that ? – orion elenzil Jan 15 '18 at 18:04
3

You can also just hook up to the "Editing Changed" from IB and create the Action to handle it

- (IBAction)txtField_Changed:(id)sender
{
   // my textfield has been changed
}
Oren
  • 5,055
  • 3
  • 34
  • 52
0

This works for me

func textView(textView: NSTextView, shouldChangeTextInRange affectedCharRange: NSRange, replacementString: String?) -> Bool {
    print("Changed!")
    return true
}
Philipp
  • 61
  • 7
-3

You can use textFieldShouldBeginEditing: method of UITextFieldDelegate. In iOS listeners are called NSNotifications

EDIT

In objective-c a lot of UIObjects have a corresponding protocol class that's called "delegate" The delegate is responsible for reacting to events. So to be able to respond or to be notified about actions you need to implement the delegate and its methods.

Cyprian
  • 9,423
  • 4
  • 39
  • 73
  • 4
    wrong OS (OSX not iOS), wrong control class (NSTextField not UITextField) – Till May 29 '11 at 02:00
  • Sorry, but Notification is not a listener. You add self as an Observer to Notification Center to receive notifications. – igraczech Sep 04 '14 at 16:44