Updating NSTableView in an instance of NSCollectionViewItem - cocoa

In my setup I have an NSCollectionView of volumes connected to the mac. For the NSCollectionViewItem's View I have an NSBox with an NSTableView inside listing the contents of that volume.
My problem comes when trying to add/remove items to the NSTableView. The NSBox seems to be initialised once, so there is only one NSTableView. This means that when I want to update the data inside the NSTableView I cannot call reloadData on an IBOutlet and have it update all the tables.
If I create an IBOutlet in a subclass of the NSBox, it is nil for the instance, so I cannot call it via that.
The closest I have come is by enclosing a #try #catch around the code that returns the object at a row in a column, an exception occurs because that item no longer exists, so I can grab the tableView and call reloadData, which seems to update that specific NSTableView.
The problem with this is that if the item removed is at the end of the table, or if an item is added, the exception won't occur as it can see all the existing items.
Has anyone had any experience with an NSTableView on an NSCollectionViewItem's View? How did you update the tables?

Put the NSBox (with its NSTableView) into its own nib. Each time you create a new collection view item, load the nib, set that NSBox as the collection view item's view, and release the NSBox.
As for feeding the table views, the easiest way is probably Bindings. Bind each column of the table view to a different property of the model object that the collection view item represents. You'll probably want to go through an array controller, of course, which means having one of those per collection view item, and adding them to an array, which you'll release in dealloc.

Related

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.

Subviews of a NSCollectionViewItem's view are always nil

I have a very basic setup with a NSCollectionView. I have a subclassed NSCollectionViewItem which is used as the itemPrototype for the collection view. The collection view item has a view.
Using Interface Builder, I added an NSImageView to the collection view item's view and connected an IBOutlet to the instance of my collection view item subclass. The property for the IBOutlet is uses retain for its memory management.
My goal is to hide or show this image view whenever the selection state for the collection view item changes. But within the setSelected: method my property for the image view is nil, even though I am 100% sure its outlet is connected, its property is set to retain and i have not unset or released the image view.
I had a similar issue with collection view items where an activity indicator added to the view was always nil too. Why does this happen and what do I need to do to fix it?
As far as I now, IBOutlets pointing to non-top level objects in nib/xib file should be defined (weak).
Are you sure you have changed the class of NSCollectionView item correctly?
When breaking in setSelected:, and doing a po self in the debugger console, are you seeing the name of your class?

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.

Global UITableViewCell identifiers, created once in storyboard and used in all tables of the app

I have an application that loads a cell in various table views. I want this specific cell to be the same across all tables view and every time i change something in its design to be populated in all views.
So far I have the cell creation method inside an object, which is call by all table views. If i make changes to that methods all table view are updated.
I have designed the cell in Storyboard and assign it a unique identifier. I want to keep it that way (not design it programmatically). So far I have to copy/paste the cell to all the tables that it is being used. Is there a solution to create a cell in storyboard that can be used in all table views without having to copy/paste.
Unfortunately we can't create a specifically table view cell in story board.
If you want to maintain a single cell instance for all the tables in the application, you need to to create a singleton instance and need to implement all the delegate and data source methods in that class. While setting the delgate and datesource objects to the table view object, you need to give the singleton instance. So that the implementation of the table view cells is single time through out the application and you don't need to copy paste all these methods for each table.
You can lay out the cell in its own xib file instead, create a UINib object from the nib, and associate that with the reuse identifier for your particular table.
Your nib must have a UITableViewCell (or subclass) as its top level object.
In viewDidLoad, you'd have something like:
UINib *sharedCell = [UINib nibWithName:#"SharedCell" bundle:nil];
[self.tableView registerNib:cellNib forReuseIdentifier:#"SharedCell"];
This way you can use the same design in several storyboards.

How to get NSTableCellView of view-based NSTableView?

I've just created my first view-based NSTableView in Interface Builder and I've correctly set up the data source and the bindings to update the views in the tableview. Each view has two labels and a NSProgressIndicator. Updating the progress indicator through the bindings and the data source works perfectly, but I'd like to change its state from determinate to indeterminate at some time. As my NSTableCellView subclass has access to the progress indicator, how can I get access to the cell view at a given row index? I've tried calling viewAtColumn:row:makeIfNecessary: on the tableview with both NO and YES for the makeIfNecessary argument, but neither seems to work.
Solution 1: In your NSTableCellView subclass add a property (IBOutlet) for your NSProgressIndicator control. Wire it in IB to set the property when the view is loaded. You can then access the progress control in your cell view subclass by using the property.
Solution 2: In IB give your NSProgressIndicator a unique integer tag. In your cell view subclass use [self viewWithTag:] to get the object.
I am not sure about the answer to your main question but you can bind the indeterminate state as well. In IB Is Indeterminate is listed in the Parameters section.

Resources