NSOutlineView with manual Cocoa bindings - macos

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.

Related

How to enable/disable editing in a view based NSTableView using bindings?

I cannot figure a way to enable/disable editing in view based NSTableViews using cocoa bindings.
I mean, I can perfectly enable/disable editing in a separate NSTextField, by binding it's "editable" attribute to a file's owner property such as
#property BOOL canModify;
(bind to: file's owner)
(Model Key Path: self.canModify)
But if I do exactly the same with a NSTextField in a view based TableView the binding seems to be totally ignored.
Also to be noticed that I can populate the table via bindings/array controllers so it's quite strange that the stuff doesn't work only for the "editable" property.
Thank you in advance
No. There's no problem in Apple's implementation of File's owner bindings for tablecellviews. I simply overlooked an IB warning.
"... Objects inside view-based cells may only be connected to the tableview's delegate."
I did set the "delegate" outlet of the TableView to my WindowController (implementing the "delegate protocol) and everything is working fine, without any double double double passages over table Cell's objectValues.
The name of your property and the key path of your binding don't match, although maybe that's just a typo: canModify vs. canModyfy ("i" vs. "y").
The editable binding should work just fine. You should check your other bindings, such as the value binding, to see if it has the Conditionally Sets Editable binding option enabled. Annoyingly, this option is enabled by default.
Lastly, you haven't explained in which NIB you're defining your cell views. Are they defined in the same NIB as the table view itself, or are they in a separate NIB? That would affect which object is File's Owner.
Even when table cell views are defined inside the same NIB as the table view, I believe they are encoded as a NIB-within-a-NIB. That is, each table cell view subhierarchy is actually encoded into a NIB blob and that NIB blob is archived into the parent NIB. When the table cell view sub-NIB is loaded, the table view's delegate is usually supplied as its owner. So, binding to File's Owner may not have the effect you expect.
For table cell views, you usually bind the subviews (like an NSTextField) to the table cell view itself, keyed off of the objectValue property.

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.

Designing UICollectionView cells in nib with Interface Builder (without storyboard)

I am trying to design a custom UICollectionViewCell prototype (in Xcode 5.0.2), however Interface Builder doesn't let me add a cell to my UICollectionView while designing a nib. I can set the number of items (cells) and Interface Builder creates and displays cells perfectly if I'm using storyboard, but I can't add a cell to my collection view in a nib. I've tried:
Drag and dropping collection view cell into collection view manually from the object library. (fails: doesn't let me drop the cell anywhere in my view)
Creating my collection view with cells in storyboard and copy-pasting the whole view into nib. (fails: collection view is copied but the cell is gone)
Creating my collection view with cells in storyboard, opening the storyboard as source code, finding my collection view cells, copying the relevant XML, opening my nib as source code, pasting it inside my collection view in XML. (fails: unable to open the nib in Interface Builder, it gives errors. When I remove the cell from source code, it opens again. Do not try this if you don't know what you are doing.)
I've also seen several questions about the same issue:
Is it possible to create prototype cells in Interface Builder without story boards?
Custom Header in UICollectionView with Interface Builder without Storyboard
Prototype Cells in a nib instead of a storyboard
They all point out to doing them programatically and/or using another nib for the cell. I know how to do them, but is there any way to design the collection view cell, inside a collection view inside the same view in a nib, just as in storyboard? Why doesn't Interface Builder let me do that in nib where it allows (and even encourages) perfectly using storyboard?
The simple answer is no, this cannot be done. Think of a storyboard as a collection of XIBs. A XIB simply defines the facets of a particular view so that it can be constructed at runtime.
Regarding collection views and their storyboard implementations, it's important to understand that a storyboard allows for nesting of viewcontrollers and defining collection views with their XIBs because that keeps the fundamental paradigm of storyboards coherent. Since a storyboard is the means of defining the "story" or scene of an application it is only natural that it allows for the declaration of the reusable views for use inside a collection view.
The same cannot be said for XIBs because the fundamental idea behind XIBs is in reusability. This will allow a collection view defined in a XIB to have any cells used with it as long as the controller registers these classes with the collection view. This way you get the benefit of reusability as another controller can use the same XIB and register different cells etc.
So I think it would be far more confusing to allow for the declaration of the supported cells of a collection view inside a XIB since that breaks the single responsibility principle(if it can be called that) that XIBs aspire to.
Your best solution would be to define a custom collection view subclass that registers the relevant cells on instantiation, and then use this class in your XIB.

Custom NSViewController representedObject doesn't update when view selection changes

I've got a custom NSViewController that's also an NSOutlineViewDataSource. I also have a window with an NSOutlineView bound to an instance of my view controller as the data source, and the NSOutlineView bound to the view: property of the custom view controller.
The controller fills the outline view fine. However, selections within the view don't automatically update the representedObject property of the controller. The only thing that seems to trigger a change in representedObject is when I call setRepresentedObject: directly... which sort of defeats the purpose.
Any idea why that might be? representedObject is supposed to update automatically, right? Thanks in advance...
If I understand your question, you are not understanding what representedObject is for. The representedObject is the model object that represents all the data that a view controller is displaying. It is not the current selection of a view showing a collection of content. The representedObject for your custom top level view controller would be an NSArray or other collection class which contains the set of data you are displaying in your view controller. Changing the representedObject for your custom top level view controller should have the effect of swapping out for an entirely new data set if the pattern is being used correctly.
Typically the view controllers for the individual elements in a tabular type view would each have their own representedObject and this object would not change. For example if you were using an NSCollectionView each element in the view is controlled by an NSCollectionViewItem which is a subclass of NSViewController. The representedObject for each NSCollectionViewItem tells it what data to present in its little view.
NSOutlineView and its superclass NSTableView are different in that their cells are often NSCells rather than full fledged NSViews unless you choose to use them this way in Mac OS X 10.7 or newer. Even in this case, you don't typically have an NSViewController subclass managing each cell. So the view controller representedObject pattern is not used at the level of the individual element that the user would select. If what you want is to track the NSOutlineView's selection, there are many NSTableView methods that let you do this.

Binding to NSTextField works; binding to NSTextView doesn't?

I've got a simple master-detail project with an array of class instances, an array controller providing a selection of a specific class instance, and an NSTableView presenting the array and the selection. My class has an NSString property, and when I bind it to to an NSTextField, everything works great.
However, when I bind the same property to the Value Path field of an NSTextView, it behaves very erratically:
Selecting among entries in the NSTableView causes no change in the NSTextView, even though the selected objects have different values for the bound property.
Nothing typed into the NSTextView is copied into the property of the selection.
The only apparent effect of the binding is that clearing the selection in the NSTableView (e.g., clicking below all of the entries) causes the contents of the NSTextView to vanish.
Any ideas?
The valuePath binding is for file paths. The value binding is for strings; there're also data (RTF/RTFD) and attributedString bindings.

Resources