Group Group Group Group Group Group Group Group Group

NSTextField - what's up with that


#1

Hi everyone. I am new to macOS - working my way through some examples and getting to grips with some of the controls before I embark on my new project. Do far I’ve tacked container controls, tableviews, delegate and actions etc so I think I am doing OK generally… however.

I am really struggling with NSTextField. I simply need (I say simply) to be able to get an event every time the text is changed. I figured it would be a delegate and that I’d use an extension like I do with NSTableView. Nothing I’ve seen by way of examples work so far and some of them seems to suggest that I need to delegate to the ‘app controller’. Then I read an example about overriding a function.

First up: can anyone share with me a simple project that has a NSTextField on a ViewController that captures the text changed events. The examples I’ve seen don’t work with Xcode 10 / Swift 4. Something always errors on compile.

I am struggling to interpret the documentation and also to understand why some controls work via delegates and some need function overrides and others seem to need to hook into notifications.
Is it me or is there a tonne of inconsistency for macOS?

Ahhh…

Any pointers much appreciated.

Dave


#2

@drenwick Do you still have issues with this?


#3

I was curious, and just made a simple Mac app. The NSTextField and all its related classes are indeed a bit of a maze now. I think it is a result of so many additions over the years, and renaming of methods from time to time.

I finally did track it down. NSTextField makes itself the delegate for NSText, and sort of buries the textDidChange() method. However its implementation calls the NSControl delegate method, which is now called controlTextDidChange().

So the following works, with Xcode 10.1, Swift 4.2, and Mac OS 10.14, with the outlets hooked up on the storyboard:

import Cocoa
class ViewController: NSViewController {
  @IBOutlet weak var textEntry: NSTextField!
  @IBOutlet weak var labelCount: NSTextField!
  var count = 0
  override func viewDidLoad() {
    super.viewDidLoad()
    textEntry.delegate = self
  }
}

extension ViewController: NSTextFieldDelegate {
  func controlTextDidChange(_ obj: Notification) {
    count += 1
    labelCount.stringValue = "\(count)"
  }
}

#4

So I did some more work on this and implemented an override of textDidChange but it’s great to know controlTextDidChange is an option too
While I am here - I was surprised to learn that keyDown doesn’t get triggered but that keyUp does !!

It’s good also to understand that it’s a bit of a maze now because when you are starting out with the frameworks it leaves you wondering what’s the best approach.

Thanks


#5

One thing about KeyUp or KeyDown is that they don’t fire when text is pasted into a text field (learned that the hard way). I have also run into an issue in iOS using shouldChangeCharactersIn on a text field to react to changes before they happen. The auto-complete would cause it to run a second time, which could change the result. So using some version of textDidChange seems like the best way to go.