Hello,
I'm using NSTableView with binding to NSArrayController without CoreData. I succeed with everything - except add a new row - object.
I know, that with add "the result of this method is deferred until the next iteration of the runloop". But I do not find any way to get the result. For remove, it's no problem although it's results are deferred as well. After remove, I do nothing but the NSTableView shows the result immediately. With add, I tried a lot, including rearrange after a certain timeInterval. No success.
The only chance I have: I append new object to NSContellers content array directly and then call rearrange. But that's not what I want.
Do you have any ideas?
Kind regards
Wolfgang
One of the quirks of NSArrayController is that it mostly doesn't matter what the object is class is set to. It only really matters when it needs to create an object on your behalf, such as when you use its 'add:' method.
I'm not entirely sure what you need to enter in IB to get to recognize a nested, Swift class type. Looking at the 'objectClass' property after setting it in code might be misleading, because the property of type AnyClass, so it displayed representation is just a human-readable form of something else, and may not be anything you can use directly. One possibility would be to add @objc(MyObjectClassName) to your MyObject definition. I believe that makes the class available to Obj-C contexts as simply "MyObjectClassName", without any namespacing (module or containing type name) complications.
The other problem with 'add:', in general, is that it creates an object by invoking its 'init' method, so there is no way to specify parameters — and, since you likely have an array of these objects because you're putting them in a table view, you probably want to configure each object differently. So:
1. If you're using 'add:' as a convenience, don't bother. It usually ends up being inconvenient before you get much further.
2. If you're using 'add:' as an actual action method (e.g. from a "+" button in your UI), don't hestitate to ignore it, and write your own action method, which you put in your window controller subclass — which is a much better place for it than in the array controller. (The view controller would be even better, if you're using a storyboard, but you've shown code using a window controller, so I'll go with that.)
3. When you get the point of having created a new object and want to add it a data model, you can do it either of two ways:
3a. Using an outlet to the array controller in your window controller, invoke the array controller's 'addObject:' method.
3b. Add the object KVO compliantly to your data model's indexed collection property. This is your "myData", but I strongly encourage you to think of it as an indexed collection property, rather than as an array. The correct way to add a new object KVO-compliantly is via a mutable array proxy like this:
myData.mutableArrayValueForKey ("myData").append (myNewObject)Because this is KVO compliant, the array controller will observe and act on the change, without any need to "rearrange" its contents explicitly.
Personally, I use 3b rather than 3a, because I hate having any references to the array controller in my code, wherever possible, because NSArrayController is a truly horrible class, useful as it is. (Note: 3b is exactly what 3a does on your behalf.) (Note: If you use 3a or 3b, you don't give a **** what the array controller thinks the object class is.)
If you follow this approach, you can create and configure your added object without needing to negotiate shark-infested array controller waters at all.
The reason [NSArrayController add:] defers its result to a later iteration of the main event loop is that it might need to display an error dialog, and it wants to do this as a sheet, which makes its actions asynchronous. If you have similar needs, you might also choose to code asynchronously like this, but if the logic of adding a new object is simpler, you don't have to bother. KVO compliance will get you the result you want.