Content Array expects to be bound to type NSObject

Error: “The Content Array binding expects to be bound to an object of type NSObject, but employees is of type [Employee]”

In XCode 8.2.1, I receive the error above when I attempt to Bind the Array Controller to the File Owner’s employees array. The Object Controller Class is set to ‘RaiseMan.Employee’. The Controller Content is set to Bind To File’s Owner and Model Key Path to employees. A red exclamation mark appears as soon as it is set to employees (which is available in the pop-up with available values to pick from). The Table View is not displaying any values and will not allow me to add anything new when running.

The Employee class is the simplest implementation from the beginning of the chapter:

import Foundation

class Employee : NSObject {
var name: String? = "New Employee"
var raise: Float = 0.05
}

I found one similar question on Apple’s forum:
forums.developer.apple.com/thread/64760

Any ideas?

-E

Did you try declaring the employees array as an NSArray?

Not like this:

var employees:[Employee] = [...]

But like this:

var employees : NSArray = [...]

Thank you for that suggestion. The approach does indeed resolve the initial binding error, but still will not allow the App to add a new item to the Array. Given the error I suspect that it doesn’t recognize the type I am trying to store (which is Employee). The new definition does not appear to provide that information.

2017-02-16 19:47:23.144863 RaiseMan[14026:50451] -[__NSArrayM lastIndex]: unrecognized selector sent to instance 0x608000245e50

It turns out the message XCode provides is not fatal… but it does persist if you use custom classes. There was another issue, related to ‘Selection Indexes’. The material neglected to mention that you have to uncheck ‘Raises for non-applicable keys’ in that section. The illustration is cut off right above that selection, so it also didn’t show anything. I mistook the XCode error as the problem with the App.

I am not really sure why XCode marks the bindings as invalid, but in the end the App does seem to work as expected. It also complains about the Table View Cell bindings (name and raise), but this works correctly as well.

Same to me, but as the book says “Do not panic if you see a red error indicator …,” I just ignore it.

With Xcode 9 Beta, adding @objc dynamic to each member seems to make things better. For Xcode 8.x.x, dynamic.

class Employee : NSObject {
  @objc dynamic var name: String? = "New Employee"
  @objc dynamic var raise: Float = 0.05
}

Try this:

Employee().value(forKeyPath: "name") as! String

Without @objc dynamic, `` the expression will cause crash with EXC_BAD_INSTRUCTION. In contrast, with it, the value of name will be returned as expected.

Search for both KVO Compliance and the keyword dynamic. They will take you a long historical story. :slight_smile:

1 Like

Additionally, with Xcode 9 Beta, to avoid another crash, it seems to require @IBInspectable like this:

@IBInspectable var employees:[Employee] = [...]

BTW, it seems that use of an array bound from the NSArrayController is up to us. Without binding to any array or set, the NSArrayController also works fine. In that case, contents will be available from:

@IBOutlet var arrayController: NSArrayController!

arrayController.arrangedObjects as! [Employee]
arrayController.content as! [Employee]

In the same order of what-user-see and in the order of object creation, respectively.

Eventually, I have succeeded to suppress the red indicator by adding @objc to class definition like this:

@objc class Employee : NSObject {
  @objc dynamic var name: String? = "New Employee"
  @objc dynamic var raise: Float = 0.05
}

However, with Xcode 9 Beta, Xcode’s behaves something weird. Right after adding @objc, Xcode struggles to find symbols and shows lots of errors at the first moment. To overcome compile errors, we might need to: Do Product > Clean. Repeatedly do Product > Build. Make some changes by adding a return key in the source file where @objc class is defined so that Xcode will recompile the source file. Wait some seconds for that Xcode’s internal cash becomes to be up-to-date.

In my humble guess, the warning message “Content Array expects to be bound to type NSObject” appears when Xcode considers the variable specified in the Model Key Path field to be inadequate. Xcode maybe solely check if the variable works with some methods defined in NSKeyValueCoding.

Confirmation failures might happen

  • if the variable is not capable of NSKeyValueCoding, which NSObject has.
  • if a class name of the variable cannot be found from Objective-C’s perspective of view.
  • if something goes wrong during confirmation.

The warning message might be somewhat misleading, and it will be fixed in the future, I think. :smiley:

Finally, a good news!

Once @objc is added to the class definition and @objc dynamic is added to the array variable definition, the red indicator has gone and MVC has started to work!

Now, any modification on the variable such as adding elements, removing elements, and assigning a new value to members of elements is automatically propagated to the table view.

@objc class Employee : NSObject {
  @objc dynamic var name: String?
  @objc dynamic var raise: Float
}

@IBInspectable @objc dynamic var employees: [Employee] = []

NSArrayController is notified the change of the array variable, i.e. employees, then it updates its arrangedObjects. NSTableView is notified the change of arrangedObjects, then it tells the change to NSTableCellView. NSTableCellView updates its objectValue. NSTextField is notified the change of objectValue, then it displays the new value on the screen. Amazing!

Confirmed with Xcode 9 Beta.

Thank you - this works…none of the tutorials I found online mentioned this fix. It was driving me crazy

Works great in Swift 5! Thanks

That was my pleasure. And thank you for the confirmation with Swift 5!