Combine in AppKit - issue with publisher(for: NSControl.textDidChangeNotification...

I'm trying to learn how to use Combine in an AppKit app I'm working on. I found an Apple Developer article that explains pretty much exactly what I'm trying to achieve, delaying input from an NSTextField with the .debounce operator. (https://developer.apple.com/documentation/combine/receiving-and-handling-events-with-combine)

Unfortunately it doesn't seem to be working for me. I have created a function in a NSTableCellView subclass that gets called as part of the cell's configuration which looks like:

Code Block    
private func watchForSearchTextEntries() {
print("Setting up search text observer")
let sub = NotificationCenter.default
.publisher(for: NSControl.textDidChangeNotification, object: searchTermText)
.map( { ($0.object as! NSTextField).stringValue } )
.sink(receiveCompletion: { print ($0) },
receiveValue: { print ($0) })
 }

When I run the app and type in that field, nothing gets printed to the Console.

As a test, I also tried adding a NotificationCenter observer that calls a method to print out the notification's object.
Code Block
NotificationCenter.default.addObserver(self, selector: #selector(receivedTextChangeNotification(_:)), name: NSControl.textDidChangeNotification, object: searchTermText)


That works as expected.

So what's going on with my attempted use of Combine?

Accepted Reply

I finally realized that I simply needed to keep a strong reference to sub. The finished code now looks something like:

Code Block
    private var searchTextObserver: AnyCancellable!
    private var item: ModelItem!
    private func setupTextObserver() {
      let sub = NotificationCenter.default
        .publisher(for: NSControl.textDidChangeNotification, object: searchTermText)
        .map( { ($0.object as! NSTextField).stringValue } )
        .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
        .sink(receiveValue: { [weak self] in
            self?.item.value = $0
        })
        searchTextObserver = sub
    }

Replies

I finally realized that I simply needed to keep a strong reference to sub. The finished code now looks something like:

Code Block
    private var searchTextObserver: AnyCancellable!
    private var item: ModelItem!
    private func setupTextObserver() {
      let sub = NotificationCenter.default
        .publisher(for: NSControl.textDidChangeNotification, object: searchTermText)
        .map( { ($0.object as! NSTextField).stringValue } )
        .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
        .sink(receiveValue: { [weak self] in
            self?.item.value = $0
        })
        searchTextObserver = sub
    }