2

In a view-based single-column NSTableView containing a default NSTextField in its Table Cell View, I'm trying to listen to confirmed user edits by connecting the NSTextField's action, within an Interface Builder view of the .xib, to a method in my ViewController for the window. But at run time (during window initialization) I get "Could not connect action, target class NSObject does not respond to -textCellChanged". I don't understand which NSObject is being incorrectly targeted, and I have many other NSViews in the window correctly connected to other outlets and actions in the same WindowController.

I see various other posts with a similar symptom, often also in the context of NSTableView, and have explored the solutions or partial solutions to those other problems in my context without success. Is there any particular magic about wiring Table View Cells in Interface Builder that I am overlooking? Or perhaps phrased differently: how is the target object actually determined at runtime, when the action is simply a class method in the File's Owner (and when does this vary for different controls all wired to the same owner of a common superview)?

Here are some particulars of context:

  • File Owner is set to a subclass of NSWindowController and Module there correctly inherited to my app target.
  • Probably relevant: I am not using Storyboards, and the top-level object in my XIB's outline view hierarchy is a Window (NSPanel), rather than an View or View Controller. The NSWindowController only appears within the XIB as the File Owner (not as its own object in Outline View).
  • In any of the various wiring scenarios I've tried (following), Interface Builder "looks like" the wiring op has succeeded. After wiring, the File Owner's Connections inspector lists the intended connection under Received Actions ("textCellChanged: ... [x] Table View Cell"), along with many other actions connecting components in the NSTableView's superview to other methods in the NSViewController.
  • Likewise, connecting the NSTextField as an OUTLET in the same NSViewController works with no problem. It's only the action (or target/action?? in IB one only sets "action") that fails.
  • The File Owner is also the data source and delegate of the NSTableView, and the NSTextField is set to Action:Send on End of Editing and Behavior:Editable. I don't think any of these are relevant to the particular symptom, which is just a failure to connect an action.
  • The NSWindowController is Swift; I have tried implementing the appropriate action within both the main NSWindowController implementation or in an extension that implements NSTableViewDelegate to no noticeably different effect.

Other posts suggest Xcode bugs in wiring, though in older versions of Xcode (I'm in 10.2). Here are various approaches I've tried, all with similar results:

  • Ctrl+Drag from Table View Cell icon in IB Outline View to NSWindowController source module, targeting there either an existing @IBAction or permitting Xcode to generate a new Connection (type Action, Object: File's Owner) and with it a new method in the ViewController
  • Reverse Drag from Source Code "left-column radio circle" next to an @IBAction to the Table View Cell in Outline View of my .xib
  • Ctrl+Drag from Table View Cell icon (in Outline View) to Placeholder/File's Owner icon, then choosing an appropriate action method from the pop-up list of methods implemented in the view controller.
  • Possibly some others

Finally, here are some related posts and how they differ:

  • This sounds like an identical symptom, but in comments OP claims to have fixed the issue by a combination of setting File Owner to the View Controller (done) and by working around blocking XCode bugs (not visible in my context).

  • This suggests I'm linking to a stale (deleted) method; definitely not the case when I allow Xcode to create the method for me.

  • This unanswered post suggests the user gave up on the situation as an IB bug and gave up in preference for a non-target/action workaround. I suppose I could pursue listening to notifications on the NSTextField as a similar workaround.

  • Finally, the accepted answer to a similar symptom here is that the connection to File Owner is incorrect in that case, where File Owner was the NSApplication object rather than the View Controller. In my case, File Owner is the View Controller object that defines these methods, so feels like the correct target.

Any stone unturned here? Thanks in advance for your help.

  • You say "File Owner is set to a subclass of NSWindowController" and "File Owner is the View Controller". Which is correct in the xib and at runtime? The target of the text field must be the delegate of the table view. – Willeke Mar 26 '19 at 12:55
  • You either renamed your property in code and you forgot that you have dangling pointer in XIB/Storyboard which still has previous property name. – Marek H Mar 26 '19 at 15:15
  • @MarekH, I don't think so. If I delete my method in source or my wire connection to it in IB, the error vanishes. Per above, the error returns either immediately after I wire-connect to an code-present IBAction or let IB add a new IBAction stub to my routine. In both cases, there's no dangling pointer at connect time. I think the problem is at run time it's trying to wire the present routine to a run-time object different from the target of other similar actions pointing from the same view to the same source object. – Nicholas Jackiw Mar 30 '19 at 15:07
  • @Willeke, thanks; I meant NSWindowController not ViewController (now fixed above). File Owner in .xib is a custom class, my descendent of NSWindowController. Top-level object in .xib outline view is a Window, custom class my descendent of NSPanel. Window's delegate is File Owner; file owner's "window" outlet is Window. File Owner is also delegate and dataSource of Table View, and target of the received action from Table View Cell (as well as many others). All of these connections work and are functional except the Table View Cell -> File Owner/NSWindowController. – Nicholas Jackiw Mar 30 '19 at 15:15
  • Do you load rows in the table view during window initialization? Do you call `makeView(withIdentifier:owner:)`? Which object is the owner? – Willeke Mar 30 '19 at 22:07
  • @Willeke, you've just solved my problem -- thanks! Following a [Ray Wenderlich tutorial] (https://www.raywenderlich.com/830-macos-nstableview-tutorial) I was supplying owner:nil, and more generally not correctly understanding the relationship between that call and the Table Cell View already defined in the NIB along with my other (already instantiated) views. If you care to repost your Comment as a proposed Answer I would be happy to Accept it! – Nicholas Jackiw Mar 31 '19 at 17:39

1 Answers1

2

The file's owner in a xib file is a placeholder object representing the owner of the nib and representing the owner object passed to makeView(withIdentifier:owner:). Pass the owner of the nib (usually the view controller or window controller) to makeView(withIdentifier:owner:).

Willeke
  • 14,578
  • 4
  • 19
  • 47
  • This was my problem -- I was passing nil rather than self when calling makeView() from within my NSWindowController/NSTableViewDelegate, so failing to receive the magic connectivity framework default initializers grant to typical View objects in NIBs objects but not to those which are only templates for views you "make" yourself. Thank you, @Willeke! – Nicholas Jackiw Apr 04 '19 at 07:14