Cocoa bindings to display NSDictionary keys in NSTableView - cocoa

I currently have a NSArrayController whose content property is (programmatically) set to an NSMutableDictionary and my UI has a single NSTableView. The information that the NSMutableDictionary contains is not set via the UI.
How would I use Cocoa bindings to display the dictionary keys in NSTableView? I already know how to use the DataSource methods, I just want to know how to use bindings for this.

I don't think it makes sense to set an array controller's content to an NSMutableDictionary. Rather, you should bind the array controller to the dictionary's allKeys property. Or consider using an NSDictionaryController, which was designed specifically for this purpose.

Related

NSOutlineView with manual Cocoa bindings

I have an NSOutlineView that is bound to a NSTreeController. The details are like this:
the treeController has class mode, and CommonListData as the Class Name, which has a "children" property
the treeController also has "content array" bound to File's Owner's "headersArray" (of type NSArray). The "headersArray" is an array of CommonListData items
the NSOutlineView has bindings for "Content" to the treeController's arrangedObjects
the view-based outlineView is designed in Interface Builder, with each cell view has lots of elements. Each element (labels, images etc) have 'value' bindings to the NSTableCellView with the relevant objectValue.xxx model key paths
The setup is fairly simple, and it all works fine in adding and deleting objects. But the problem is that it doesn't use any of the NSOutlineView / NSTableView animations when adding or removing items from the outline view. The table just reloads itself if I add or remove any element to the treeController, or directly to the headersArray's children objects. I'm not sure if that is a limitation with Cocoa Bindings or what.
In any case, I am consider whether I can disable all the bindings and do this manually. The only drawback is that the NSOutlineView cell views have complicated elements on them, and I don't want to have to map the view elements to the data in code. Ideally it should keep the bindings in the NSTableViewCell.
So my question is:
Is it possible to keep the bindings within Interface Builder in a NSTableCellView, but not bind the content to the treeController? Or is there an alternative to binding "arrangedObjects", such that adding and removing data from the NSTreeController doesn't trigger an update to the UI?
It would help to have some more control over the bindings, so that I can trigger the animations correctly, and not have it just jump around with every update.
I believe the bindings of the views within the cell view are independent of the bindings of the outline view's content. Whether the outline view uses bindings or not, it eventually sets the objectValue property of the cell view. So long as that's done in a KVO-compliant manner (which it is), any bindings to that property will work.

NSTableView & CoreData: Delete Object at clicked row

I am pretty new to Core Data and am currently working on a small (OSX) app that uses an NSTableView to organise objects. I would now like to delete a row/object with the click of a button on that targeted row.
I access the managed object within the table controller by calling [NSApp managedObjectContext] (still trying to figure out that dependency injection thing) but I can't easily delete an objectAtIndex: like I used to with the array (which has now been replaced by the core data stack, right?).
How do I identify the object to be deleted? And consequently, how can I cleanly remove it from the stack?
This is probably a really basic question but I couldn't find any resources on it. Bindings obviously don't work because the row does not get selected before the click occurs.
Any help is much appreciated!
Bindings would work, in that you could have the button's IBAction query the objectValue for the parent NSTableCellView. Once you have that objectValue, you could call the bound arrayController to delete the object, and then the cell/row would disappear.
So, if you have a tableCellView that has a delete button with an IBAction, within that IBAction, you could get the sender's superview, ensure it's an NSTableCellView, get the objectValue, and call [myArrayController removeObject:...]
As it says in the NSTableCellView class reference:
The objectValue is automatically set by the table when using bindings or is the object returned by the NSTableViewDataSource protocol method tableView:objectValueForTableColumn:row:.
This is actually a typical pattern with views in cocoa. objectValue or often representedObject are properties on the views that refer to the data model objects they represent, so if you have a view pointer from sender on the IBAction, you can get the related data model object. And if you're using bindings and a controller, you can then just have the controller remove that object.
With bindings, you will often create buttons that need IBActions attached, rather than some direct binding. But those IBActions can most definitely interact with the controller and not the view.
And with core data, array controllers are really slick vs. assuming you have to do it all programmatically.

Programmatically update a TableView that is governed by Cocoa Bindings

I'm fairly new to obj-c and cocoa so please bear with me:
I have a NSTableView set up with cocoa bindings which works as expected with the simple -add -remove, etc methods provided by an instance of NSArrayController in my nib. I would like to programmatically add objects to the array that provides content for this controller (and hence for the table view) and then update the view accordingly.
I current have a working method for adding a new object to the array (verified by NSLog) but I can't figure out how to update the table view.
So: How do I update the bound tableview? (ie, after I have programmatically added objects to my array). I'm essentially after some view refreshing code like [view reloadData] in glue code, but I want it to work with the bindings I have in place.
Or is there a KVC/KVO related solution to this problem?
Code Details:
AppController.h
#interface AppController : NSObject
#property NSMutableArray *clientsArray;
-(IBAction)addClientFooFooey:(id)sender;
#end
AppController.m (note, I also have the appropriate init method not shown here)
#implementation AppController
...
-(IBAction)addClientFooFooey:(id)sender{
[self.clientsArray addObject:[[Client alloc] initWithFirstName: #"Foo" andLastName:#"Fooey"]];
//Need some code to update NSTableView here
}
#end
Client.h just simply defines two properties: firstName and lastName. The 2 columns of an NSTableView in my mainmenu.nib file are appropriately bound to these properties via an array controller bound to my AppController instance.
On a side note/as an alternative. How could I add functionality to the existing NSArrayController method -add, ie, something like: -addWithFirstName:andLastName and still have this compatible with bindings?
You have two main options for doing this provided your array controller is bound to clientsArray.
The first way is to just use the array controller's addObject: method instead of adding objects directly to clientsArray.
The other way is to keep your current addClientFooFooey: method but wrap your existing code with these two lines:
[self willChangeValueForKey:#"clientsArray"];
[self didChangeValueForKey#"clientsArray"];
This tells the KVO system that you are making a change to the array so it will go and look at it again.
The first option is the most straightforward, but if for some reason you need to update the array directly just let KVO know you are doing it.

Binding an NSViewController's representedObject

Is it possible to bind the representedObject property of a NSViewController to an NSArrayController's selection property (which is a NSManagedObject)?
[self.ressourcesViewController bind:#"representedObject" toObject:self.ressourcesController withKeyPath:#"selection" options:nil];
This always gives me the no selection placeholder for some reason!
this is possible by using the keypath selectedObjects.#lastObject !
Although i don't know how standard conform this is, since bindings are meant to synchronize view objects to controller objects. What i do is synchronizing 2 controller objects..
On the other side, using bindings just saves some code, needed instead to implement it manually via KVO and KVC.

Xcode, OS X: viewing a simple NSMutableArray

Relative newbie question. My app has a simple NSMutableArray of NSNumbers. (about a dozen integers) I'd like my UI to have a view displaying the numbers so that the user knows what's in the array. I want the contents of the view to be current, so I think I want a binding to the array (or its contents). Is there a simple way to do this?
I think I can figure this out if I change my model so that the NSMutableArray contains a custom class having a setter and getter to a declared property (following Lucas' YouTubtorial on NSTableView bindings), but I would think that there might be a simpler way, one that allows me to use my array of NSNumbers. I'd have to do a fair amount of editing if I have to redo my NSMutableArray. Thanks ...
You can use plain old NSNumbers (or anything else) in your model, no need to use a custom model class. However, you could create an NSValueTransformer subclass if your model data needs any special formatting for your view.
In your NIB you will have an NSTableView and an NSArrayController.
Bind the Value property of a TableView column to the NSArrayController, controller key = arrangedObjects, Model Key Path is empty (because you're viewing the NSNumber instance itself, and not a property of NSNumber).
Bind the Content Array property of NSArrayController to your model (the NSMutableArray of NSNumbers). This is probably a property on your view controller or app delegate.
That's about it. You can also hook up buttons to the add: and remove: actions on the NSArrayController, and you'll be able to add and remove items from your array.
Also, you need to send a KVO notification whenever your NSMutableArray changes. For example, say your NSMutableArray is exposed through a property called "numbers":
[self willChangeValueForKey:#"numbers"];
[_numbers addObject:[NSNumber numberWithInt:123]];
[self didChangeValueForKey:#"numbers"];
You get these notifications for free if you set the "numbers" property to a new value:
self.numbers = [NSMutableArray arrayWithObject:foo];

Resources