Doing something wrong with bindings, can't find out what - objective-c

I've a mutable array that holds instances of a model object. That model object has several properties one being "name". I have no problems initialising or populating the mutable array.
I've a window with a drawer. I added a table to the drawer, the idea being that the drawer would use the table to display several instances of the model object.
I added an nsarraycontroller to the xib of the window that has a drawer. In the Array Controller Properties I've set the Object Controller to be an instance of the model class. On the Array Controller Bindings I set the Controller Content to point to the File Owner and set the Model Key Path to the name of the array.
On the table, I bind the content to the Array Controller, the Controller Key to arrangedObjects and Model Key Path to name.
My problem is that although the mutable array has been properly initialised and populated I can't see a single entry on the table on the drawer. Am I missing something here?

Two possibilities:
First: you might have bound the wrong thing (your description here is a bit ambiguous). Bind each table column's "values" to the array controller's #"arrangedObjects.propertyName" (like arrangedObjects.firstName for the First Name column, etc.). There are alternative ways to bind the whole table, but you probably aren't binding the column's values, just the table's content.
Second: it's also possible the accessor to your model object isn't KVO compliant. Make sure proper KVO notifications wrap your setter accessor for your model array. If you've #synthesize'd it, all should be well. If you've hand-coded your accessors, all might not be well. :-)

I assume you bound the tablecells table columns to the arraycontroller? I don't think Interface Builder will let you do anything else. Otherwise, it sounds like you have it configured properly.
I would recommend ibtool for troubleshooting these kinds of problems. It's a command line tool that does a text dump. You can inspect bindings in a more compact form than using the GUI in Interface Builder.

Related

iOS ARC with when two objects need a pointer to the same thing

I'm going through my code to make sure that all of my properties have the proper weak/strong modifier and I ran across this situation which I don't know what to do with. Keep in mind that I'm fairly new to iOS programming.
I have a normal MVC hierarchy where my controller creates an object called FieldManager. This FieldManager is used by my controller to dynamically create textfields. However, this FieldManager also needs to be used by the controller's model to periodically query the manager to find out information about the fields (such as is it required, should it's text be capitalized...etc).
So to summarize, I have a controller which creates an object that is used both by the controller and the controller's model. Therefore, I don't know if I should make the model's reference to FieldManager a weak property or the controller's reference to it a weak property. It seems that I should make both weak properties, otherwise FieldManager will get released. What should I do?
Thanks.
Things like that should belong to your model, so the way to go is to have a datasource.
Your controller asks the datasource to create and return the textfields, the datasource contacts the model and asks for a field manager for that model.
That's the way I would do it...

Can I use an NSDictionaryController for a dictionary of dictionaries?

I have a plist file that holds information I need to display in an app organised as a dictionary of dictionaries. I've just started programming Cocoa so am not sure the best way to go about this. Obviously I can do it all manually, and code up the loops and add the data to the UI elements, but it seems to me that bindings and the provided controllers should let me do this more easily.
I was specifically wondering if there was a direct way (e.g. using mostly Interface Builder) to link the NSDictionary I get from reading the plist file, that itself contains further NSDictionary elements, which in turn contain name-value string pairs, to an appropriate user interface element -- probably an outline view or a browser.
Alternatively, the data would fit into a function browser type panel (like in Excel) where the top level keys are categories of functions, the next level are functions in that category, and I can just populate a text area with the lowest-level details -- i.e. the value data from the final dictionary.
I don't think you are going to be able to do this with an NSBrowser or NSOutlineView. The reason I say that is because if you are using bindings with those views you need to use an NSTreeController. NSTreeController provides the ability to specify which keys in your model indicate whether or not the current object has children objects (isLeaf) and how to access the children objects (children).
So if you are going to use one of those two views, you must be able to add additional keys and properties to your model to do so. Many times when I work with NSOutlineView and NSBrowser I find it easiest to skip bindings altogether and just use the all delegate & datasource methods. They require more code but they aren't hard to put together and sometimes I prefer them to bindings if my data model is complex or if the data is not in a format that is easily pumped through an NSTreeController.
However you could use an NSTableView by doing the following.
Create an NSDictionaryController in your NIB.
In the controller that reads in your plist, create an outlet for the NSDictionaryController and hookup the outlet using Interface Builder.
In the code that reads the plist, add an additional line of code that set's the NSDictionaryController's content to the root dictionary from the plist.
In your NIB, create an NSArrayController. Bind the array controller's "Content Array" binding to the NSDictionaryController. For the "Controller Key" binding property, specify "arrangedObjects".
Now take an NSTableView and place it in your NIB. Bind each of the NSTableColumn's "Value" bindings to the NSArrayController and for the "Controller Key" binding property, specify the key from the dictionary whose value you want to display in the table column.

Bindings vs IBOutlets in Objective-C/Cocoa

I'm going through a simple Objective-C/Cocoa program to try and learn the language and am getting a little confused about how some things are linked from the code I write to the interface builder.
For example, I have a simple NSString:
#property (assign) NSString *letters;
And in my interface builder, I have a text field and I use the text field's bindings to connect it to letters.
However, the example also has this:
#property (assign) IBOutlet NSArrayController *wordsController;
In the view I have a table that continuously changes and shows different words and those words are stored in an NSMutableArray. I suppose I can understand that I just can't bind the array to the the table because there are some more complexities. So in the Interface Builder I create an Array Controller and bind it to the table. In the Array Controller's bindings, I bind the Array Controller to the array of words.
I understand that the last thing I have to do is also bind the Array Controller to my NSArrayController object as well. I don't understand why I do this through the main controller object by making a connection between this outlet and the wordsController. In the Array Controller's bindings section there's a greyed out option, Content Object, which says "An NSArrayController that the NSArrayController treats as its content." Why wouldn't I set the binding here? What is the significance of it being an outlet and why is it different than my NSString letters?
Thanks
You are confusing bindings and IBOutlets. This is not unreasonable -- it's a lot of Control-dragging of connections and it can be hard to keep clear what's going on. Let me try to explain:
Bindings are a way to let Cocoa handle the mechanics of keeping a model (some collection of data, even something as simple as a single NSString) and a view (an object which displays on the screen) in sync. When you "bind" your NSString to a text field's value, you are asking the framework to communicate changes to the string or the text field "behind the scenes"; your object which owns the string gets notified to change the string's value when the text field changes, and vice versa.*
A similar situation applies to your mutable array, array controller, and table view. You're essentially right about the complications: the mutable array and the table view don't know how to talk to each other; the array controller stands in between and facilitates: ("Okay, tableView wants to know what to put in row i. Array, give me your object at index i." :) In the past, you would've had to write that code manually, and it looked very similar every time you did so.
That's what the bindings do. They are a way to reduce boilerplate code. The IBOutlet to the array controller gives your object a way to send messages to the array controller, if necessary. One simple example of why you might need to do this is to allow a menu item to trigger a method in the array controller; a document object or another controller might handle the action from the menu item and call the appropriate message on the array controller. You can also ask the array controller for its arrangedObjects to get, for example, the sorted and filtered version of its content array.
* One side note here is that your NSString property should almost certainly use retain, not assign. The object that contains this variable should be responsible for its memory.

What do you need to implement to provide a Content Set for an NSArrayController?

Heys,
I am writing something in Xcode. I use Core Data for persistency and link the view and the model together with Cocoa Bindings; pretty much your ordinary Core Data application.
I have an array controller (NSArrayController) in my Xib. This has its managedObjectContext bound to the AppDelegate, as is convention, and tracks an entity. So far so good.
Now, the "Content Set" biding of this NSArrayController limits its content set (as you'd expect), by a keyPath from the selection in another NSArrayController (otherAc.selection.detailsOfMaster). This is the usual way to implement a Master-Detail relationship.
I want to variably change the key path at runtime, using other controls. This way, I sould return a content set that includes several other content sets, which is all advanced and beyond Interface Builder.
To achieve this, I think I should bind the Content Set to my AppDelegate instead. I have tried to do this, but don't know what methods to implement. If I just create the KVC methods (objectSet, setObjectSet), then I can provide a Content Set for the Array Controller in the contentSet method.
However, I don't think I'm binding this properly, because it doesn't "refresh". I'm new to binding; what do I need to implement to properly update the Content Set when other things, like the selection in the master NSArrayController, changes?
However, I don't think I'm binding this properly, because it doesn't "refresh".
This most often means you are assigning directly to the instance variable, not using KVC-compliant accessor methods nor posting KVO notifications.
The general solution is to create accessor methods for the property and then use them everywhere, including inside that class, except in its init and dealloc methods.

Binding an NSPopupButton to an NSDictionaryController

I'm trying out some MacOS programming and having some trouble understanding how bindings work with an NSPopupButton. I'm interested in binding to an NSDictionaryController (I don't think I need an intermediate NSArrayController but if that is the best way, I'm open to it).
I've created a controller object that has a property 'db' which has a property 'species' which is an NSMutableDictionary. The 'species' dictionary has ID's for keys and Species objects for values. Species objects have a description property. In InterfaceBuilder, I've created MyController, NSDictionaryController, and an NSPopupButton. I would like to populate the popup with Species.descriptions. When selected, I need access to the corresponding ID.
I've setup the NSDictionaryController to bind 'Content Dictionary' to MyController with Model Key Path 'db.species'. With NSPopupButton, so far I've bound 'Content Values' to NSDictionaryController with controller key 'arrangedObjects' and Model Key Path set to 'value.description'.
This seems to work getting the list populated. My main question is what the best way to wire up the selection is. Ideally, I would like to wire selection to the NSDictionaryController so that I can use the NSDictionaryController to access the selection. One reason for this is so that I can wire other controls to the NSDictionaryController to see the current selection. If not, should I wire to a property in MyController or something? Just looking for the best practices. I would like as much to be through the Interface Builder mechanisms so that I can easily reuse the model and controller design in another application with a different view.
Update using Brian's answer as guidance:
NSPopupButton:
bind Content to NSDictionaryController->arrangedObjects->value.description
bind Content Objects to NSDictionaryController->arrangedObjects->key
bind Selected Index to NSDictionaryController->selectionIndex
bind NSDictionaryController->db.species
Everything seems to work. I can grab the object from the controller with [[[controller selectedObjects] lastObject] value]. It's in an array of selected objects with key, value pairs, I believe.
I've never tried this with an NSDictionaryController, but I think you would want to bind the contentObjects of the pop-up to the dict controller's "arrangedObjects.key" and the selectedObject binding to the dict controller's "selection" key. The contentObjects binding would specify the IDs as being the underlying objects represented by each menu item. Then when an item is selected from the pop-up, the selectedObject binding would set the ID corresponding to that menu item as the selection of the dict controller.
I would like to populate the popup with Species.descriptions. When selected, I need access to the corresponding ID.
Bind content to the dictionary controller's arrangedObjects.value (don't include description—the pop-up button will do that for you) and contentObjects to the dictionary controller's arrangedObjects.key.
For more info, see NSPopUpButton in the Cocoa Bindings Reference.
(I notice it describes content as “An NSArrayController instance …”. Dictionary controllers are array controllers, so that shouldn't be a problem, but binding to a property of the controller may be. Something to watch out for.)