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.
Related
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.
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.
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.
(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.
I'm having trouble converting my Cocoa project from a manually-synched interface model to a bindings model so that I don't have to worry about interface glue code.
I followed the CocoaDevCentral Cocoa Bindings tutorial to make sure that I had covered all the bases, but things aren't working correctly. I have a master-detail interface, but I'm having trouble even getting the master portion of the interface to work correctly. No data is showing up in the master column, even though I've set up the bindings model similar to how it is shown in the tutorial. I've made sure all my controllers and objects have -(id)key and -(void)setKey:(id)key methods so that they're bindings-compliant, I've created a ControllerAlias object in my nib, connected it to my controller, created an NSArrayController that binds to one of the NSMutableArrays from the class that ControllerAlias connects to, made sure to set the type of objects that are contained within the array, and then I've bound a table column to the NSArrayController.
I'm getting no errors whatsoever in the Console, and setting NSBindingDebugLogLevel to 1 doesn't produce any errors either, that would help me figure out what the problem is.
The only other thing I could think of to make sure that things are working correctly is to check that the NSMutableArray that connects to the NSArrayController actually has something in it, and it does.
Any suggestions? What other typical pitfalls are there with Cocoa bindings that I should check?
Have you put a breakpoint in your key: method to determine if it is getting called or not? If it isn't, then that would indicate that something isn't set up correctly for the binding in the table column (since you have verified that your array does have items in it).
I don't think that you need to create an Object Controller anymore (that tutorial is a bit out of date). Just create an Object in your NIB, and set its class to your Controller class. You can set up the bindings directly through it instead of the ObjectController.
To set up a binding, I do the following:
Create an instance of my controller in the NIB.
Create an NSArrayController, bind it to an array in my controller.
For each column in the table, bind the value to a member of an object in the array controller.
That should be all that you need to do - I think they've cleaned this up quite a bit since bindings were first introduced a few versions ago.
I've created a ControllerAlias object in my nib,
What is a “controller alias”? Is this a model, controller, or view?
connected it to my controller,
What do you mean?
created an NSArrayController that binds to one of the NSMutableArrays from the class that ControllerAlias connects to,
Classes don't have NSMutableArrays.
What property of the array controller did you bind?
What object did you bind it to?
What key path of that object did you bind it to?
… and then I've bound a table column to the NSArrayController.
What property of the table column did you bind?
Which property (key path) of the array controller did you bind it to?
So in my original code, I was modifying the array (which the NSArrayController was representing) in awakeFromNib, not in init, so the changes weren't being reflected in the interface since I wasn't modifying the array via a key-value observing method.
I changed the code from
theArray = [[NSMutableArray alloc] init];
[theArray addObject:newThing];
to:
theArray = [[NSMutableArray alloc] init];
NSMutableArray *bindingsCompliantArray = [self mutableArrayValueForKey:#"things"];
[bindingsCompliantArray addObject:newThing];
I think the other solution is to do the loading in the -(id)init method instead of the -(void)awakeFromNib method, but that required a larger refactor, so I didn't do that.
I figured this out by adding a button to create a new thing in the array list via the NSArrayController, and when I clicked the button, a new thing was added to the array and my existing array magically showed up as well.