NSArrayController not picking up data merged from another context - macos

So, i have a simple table view and my column 'Name' is bound to NSArrayController. The NSArrayController is defined with Entity type and is going to hold Person objects. I have checked "Prepares content" in the XIB file. In my application, i create and insert a managed object called "Network". This class has delegate methods that handle data incoming from the network. When my updateNotificationMethod is called, i create my Person managed object and insert it into the managed object context of "Network".
The above works like charm and i am able to display the names in the table view without any issues. However, if i handle the notifications in a thread that has a new managedObjectContext and i handle NSManagedObjectContextDidSaveNotification in my main thread to merge the changes into my main managed object context, then i don't see any updates in my table view.
Shouldn't the NSArrayController be aware of the new managed objects merged and display those?
Any ideas on what i am missing here?

If you create "Network" on the main context and optain to it with [network objectID] in your background thread make sure you do a save before entering the background thread. Otherwise the objectID of "Network" will be temporary and lead at the end not to the correct object.
Everything else looks fine to me.

Related

Core Data not loaded into NSArrayController IB binding

All,
I am at my wits end trying to figure this out. I have a NSViewController that contains a NSArrayController and a table whose dataSource is set to the view controller. The NSArrayController is setup in IB to contain Core Data entity objects. Prepares Content and Auto Rearrange Content are set to YES. The MOC binding is set. There are bindings for a filterPredicate and a sortDescriptor. When my NSViewController is loaded, the method numberOfRowsInTableView: is called, but my NSArrayController contains no data. After everything is displayed/loaded, the NSArrayController seems to contain the data (if I add another Entity object, all the objects are displayed). I've tried calling rearrangeObjects, but that doesn't seem to work. Any ideas?
As you set managed object context in IB with help of binding the NSArrayController's fetch is executed as a delayed operation performed after its managed object context is set (by nib loading). This therefore happens after awakeFromNib: and windowControllerDidLoadNib:.
So when the view controller is loaded the method NumberOfRowsInTableView: is called before NSArrayController's managed object context property is set. Hence, at this moment NSArrayControoler returns zero.
When you reloadData for your tableView NumberOfRowsInTableView: is called again and at this moment NSArrayController contains data as its fetch has been already executed.

Sharing NSArrayController Between Nibs

I have an Core Data-based iTunes-like app I'm building that has an NSTableView in the main window and allows the user to select items in the table view and perform a "get info", like in iTunes. Currently I'm working on the single-item get info window, which displays when the user selects a single item in the main window (which is in MainMenu.xib) and pressed Cmd-I. This brings up the single-item get info window (in SingleItemGetInfo.xib).
The table view in the main window is populated via bindings to an NSArrayController. If I put an NSArrayController into the SingleItemGetInfo.xib file, I understand that's going to be a different instance of NSArrayController.
So, what's the proper way to bind the fields in the single item get info window to the selection the user has made in the main window's table view?
MainMenu.xib's Array Controller bindings:
Managed Object Context: AppDelegate.self.managedObjectContext
MainMenu.xib's Table View bindings:
Content: Array Controller.arrangedObjects
Selection Indexes: Array Controller.selectionIndexes
Sort Descriptors: Array Controller.sortDescriptors
This will work mostly the same way it does when the master and detail views are in the same window. The primary difference is that you need to bind the selection of the array controller in the detail xib to the selection of the master array controller.
It depends on how you have your app organized as to how you accomplish this. If both views are run by the same object then you can just make the master array controller an outlet connected to the controller (#property IBOutlet NSArrayController *masterArrayController;). Then in the detail xib you can bind the selection of the detail array controller to the selection of the master array controller.
If each view has its own controller you might also consider just passing the managed object from the master view to the detail view. Then you can bind to each of the attributes of the managed object in your xib file (i.e. bind to File's Owner self.detailObject.fullName). If you pass a reference I think all of the changes will go right back into the managed object context.

Cocoa Bindings error

Trying to wrap my head around cocoa bindings can't determine the reason for this error
I Have a simple app, in which, the app delegate passes the Managedobjectcontext to Window Controller, which passes it to a view controller. The nib associated with view is a viewbased table with array controller.
I initiated a few managed objects in the app delegate, when I run the application the table is populated with the objects however the following error is thrown
[_NSControllerArrayProxy firstIndex]: unrecognized selector sent to instance 0x100165510
Since there is very little code, not sure how to debug this
Thanks Anoop, your second link solved my problem I had the controller key for Selection indexes set to arrangedObjects, I changed this to selectionIndexes and all is working.

Calling up a specific record in Core Data

I'm setting up an edit window for a player to edit his user data. I've got all of the fields on the edit form bound to the appropriate Core Data entity (via an NSArrayController), and I've got an awakeFromNib method installed to handle calling the record, but I'm not sure what to put inside the method to get the record to display.
Ultimately, my goal with this is to set it up so that the application checks whether an entry exists for the user, and create one for him if there's no entry in the table.
You should look at using a NSObjectController or NSArrayController rather than binding directly to the NSManagedObject. The controllers work properly with bindings and your data will display nicely and changes you make will be propagated via the controller to your NSManagedObject.
You can set the object used by the controller in your awakeFromNib. On NSArrayController use the setSelectionIndex:(NSUInteger) index message and then to avoid empty selection send it the setAvoidEmptySelection:TRUE message
Hope that helps.

Binding to a NSViewController's representedObject

(Abstract: bindings work in code, but not in IB)
I have a window managed by a NSWindowController. To the left of the window is a source view. To the right is a table view showing the elements of the currently selected source.
I have set up a NSTreeController within my window XIB. I want its contents to be used for the source view. It's selection will drive the table view.
I am trying to split this up using NSViewControllers. One view controller will load a NIB containing the source view. Another view controller will load the table view.
Seeing that I need access to the NSTreeController within the source view controller, I have set it to be the view controller's representedObject. (Actually for this setup to be done by the time awakeFromNib is called on the view controller, I have turned representedObject into an IBOutlet).
All works fine when I wire my source view up in code:
[outlineView bind:#"content"
toObject:sources
withKeyPath:#"arrangedObjects"
options:nil];
[outlineView bind:#"selectionIndexPaths"
toObject:sources
withKeyPath:#"selectionIndexPaths"
options:nil];
[[outlineView tableColumnWithIdentifier:#"Title"] bind:#"value"
toObject:sources
withKeyPath:#"arrangedObjects.title"
options:nil];
I am however unable to reproduce this using Interface Builder. Thing is, here the "controller key" textfield is grayed out. Thus I bind column's "value" to the file owner using a model keyPath of "representedObject.arrangedObjects.title". This does not show the desired behavior. Actually an exception is thrown: -[NSProxy doesNotRecognizeSelector:_mutatingNodes] called!
How can I use representedObject in IB?
Can I create a controller in IB which acts as proxy to representedObject?
Could I set-up a tree controller in the source view XIB which during NIB loading gets swapped out for the representedObject?
I moved away from using representedObject. It appears that is meant only for model objects.
I now pass in my tree controller using a custom outlet. I continued setting up and tearing down the bindings in code.
I’ve similar issues when I try to pass a reference to an object controller (NSTreeController in my case). I don’t think this is how Apple wants you to use their KVO-compatible controllers. The exceptions look like they’re XIB-unarchiving & timing-related.
The trick is not to pass the controllers, but to pass the underlying data and keep the selection in sync.
This way you can set up your bindings in a storyboard and won’t get any exceptions. You’ll have to set up a new instance of an object controller for every child view controller (copy & paste in Storyboard once you configured the first one works). For a detailed example take a look at another answer that gets much more into detail.

Resources