1

For a MacOS app I'm building with Xcode/Swift, I'm trying to call a function when the value has changed in a NSTextField (while the user is typing). So I've added a notification center observer:

import Cocoa

class ViewController: NSViewController, NSTextDelegate {

    @IBOutlet weak var textField: NSTextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChange(_:)), name: Notification.Name.NSTextDidChange, object: nil)
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    func textFieldDidChange(_ notification: Notification) {
        print(textField.stringValue)
    }
}

This works fine. But now I want it to apply to a specific NSTextField, so I set the object in the observer:

NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidChange(_:)), name: Notification.Name.NSTextDidChange, object: textField)

Now it suddenly doesn't work anymore, and I can't seem to figure out why. Just starting out with Xcode and Swift. I've been searching for a solution all weekend, but most answers I find apply to iOS apps, older versions of swift, Objective-C etc.

generator
  • 115
  • 1
  • 7

2 Answers2

1

The problem is that NSTextDidChangeNotification is one of NSText's notifications, and NSTextField does not inherit from NSText. The reason you're seeing those notifications at all is because NSTextField's uses field editor, which is an instance of NSTextView, which is a subclass of NSText, to do its actual editing, and the notification's object property will be the field editor rather than the original NSTextField.

If you register to receive NSControlTextDidChangeNotification notifications instead, you should be able to specify the text field as the object and have it work.

Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
1

There is another approach, with just .isEditing method on your selected UITextField (and Swift 5).

First, declare your Observers in viewDidLoad():

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

Then

@objc func keyboardWillShow(notification: NSNotification) {

        if <YOUR_UITEXTFIELD_HERE>.isEditing {
            if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
                if self.view.frame.origin.y == 0 {
                self.view.frame.origin.y -= keyboardSize.height
                }
            }
        }
    }

@objc func keyboardWillHide(notification: NSNotification) {
        if self.view.frame.origin.y != 0 {
            self.view.frame.origin.y = 0
    }
robo
  • 11
  • 1