0

I have a NSTextField and I would like to execute a callback whenever the text inside it changes. The callback would be to enable a disabled "save" button at the bottom of the form.

What I managed to do so far is sub-class NSTextView in order to override textDidChange(notification)

import Cocoa

class MyTextField: NSTextField {

    override func textDidChange(notification: NSNotification) {
        super.textDidChange(notification)
    }

}

After that, I didn't manage to execute a function inside my ViewController. I tried using NSNotificationCenter to trigger some kind of global event that I could catch inside the ViewController like so :

//MyTextField.swift

import Cocoa

class MyTextField: NSTextField {

    override func textDidChange(notification: NSNotification) {
        NSNotificationCenter.defaultCenter().postNotification(notification)
        super.textDidChange(notification)
    }

}


//ViewController.swift

import Cocoa

class ViewController: NSViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: "fieldTextDidChange:", name: "NSTextDidChangeNotification", object: nil)
    }
    override func viewDidAppear() {
        super.viewDidAppear()
    }

    func fieldTextDidChange(notification: NSNotification) {
        print(notification, appendNewline: true)
    }
}

But I get a runtime error when typing inside the field : Thread 1: EXC_BAD_ACCESS (code=2, address=0x7fff5f3fff70) on the line that calls postNotification()

How can I manage to trigger a callback on text change of a NSTextField ?

EDIT

Sub-classing and sending a notification is silly as pointed out by matt. There is no need to sub-class the text field. Simply observing the NSTextDidChangeNotification is enough to react to the event I was looking for. I had tested this but I was missing a colon at the end of the selector on top of this, so I thought it was not the correct method. It is indeed the correct method.

beeb
  • 1,187
  • 11
  • 32
  • It's not needed to subclass `NSTextField`. Connect the delegate property in Interface Builder to the appropriate class and override `controlTextDidDidChange` - - `override func controlTextDidChange(notification : NSNotification) { let textField = notification.object as! NSTextField }` – vadian Sep 03 '15 at 13:37
  • I haven't tested your solution since I could do it with the notification center but it sounds like it could work as well. In my case (using the `NSTextDidChangeNotification`), the object reference passed in the notification was the NSTextView inside the NSTextField. I had to get the superview of the superview to get to the NSTextField. – beeb Sep 03 '15 at 14:14
  • not *it could* - it does ;-) – vadian Sep 03 '15 at 14:24

1 Answers1

1

The reason you are crashing is that your selector is wrong. It should be selector: "fieldTextDidChange:" (notice the final colon).

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    But on the whole your code is extremely silly. Why would you post a notification in response to receiving a notification??? Just receive it once in the place where you want it. Otherwise you're in danger of receiving it in that place _twice_. – matt Sep 03 '15 at 13:37
  • This is correct in fact. When I get rid of the `postNotification` part, all my keystrokes are doubled. I removed the `postNotification` line and changed my view back to a normal `NSTextView` and now I can listen to the notification properly. Thanks ! The main issue was the colon missing at the end of the selector. – beeb Sep 03 '15 at 13:39