Online Book Reader

Home Category

Learn Objective-C on the Mac - Mark Dalrymple [51]

By Root 1017 0
table of data just because a single value has been changed, but don’t worry: NSTableView uses “lazy loading,” and normally only requests content for a given row when that row is about to be displayed. You might have a million rows of content, but if you never scroll past the first 30, no more than the first 30 are likely to be loaded by the table view. Likewise, telling a table view to reload its data will only make it load the visible rows immediately, the rest will only be reloaded when they scroll into display.

At this point, you should be able to compile and run your app, and you should see roughly the same thing you saw at the end of chapter 4, plus a big empty table view and a couple of buttons that have no effect. Time to fill that table view with villains!

The Table View Needs Your Help


We’ve told the table view to load its content, but it can’t do anything until we implement some methods from the NSTableDataSource protocol in the object we connected to the table view’s dataSource outlet: our AppController. NSTableDataSource is an informal protocol, similar to most delegate protocols, which means that you don’t have to declare that your class conforms to the protocol. As a result, implementing the NSTableDataSource methods is, as far as Objective-C is concerned, optional. In spite of that, there are a few methods that are in fact required for the table view to display anything: numberOfRowsInTableView:, and tableView:objectValueForTableColumn:row:, both of which are used by the table view to prepare content for display. Here’s how these should be implemented in AppController.m:

The first method should be self-explanatory: we just return the size of the array so that the table view knows how many rows it needs to display. The second method is called by the table view each time a cell is going to be displayed in the table. We’re given a pointer to the column that the cell is in, and an index number indicating which row it’s in.

The row index number is the same as the index number for the relevant object in our content array, so calling [villains objectAtIndex:rowIndex] returns the relevant model object from villains. As you may recall, the model objects we’re using are in fact just NSMutableDictionary instances, with all their values accessible by keys. When we configured the identifier attribute of each column in our table view, we used the same key names that our model objects use, so we retrieve that key from the table column, and use that to get the relevant value from the model object.

For example, when the cell in the top row under the “Name” column is about to be displayed, this method will be called with a rowIndex of 0, and a TableColumn pointing to the “Name” NSTableColumn. We use the 0 to specify which villain to grab from our villains array, then we use value returned by the table column’s identifier method, @”name”, to retrieve a value from the chosen villain.

If that’s not quite sinking in, here’s a slightly longer (in terms of lines of code, not runtime) way to implement the same method, which may clarify it for you:

Now you should be able to compile and run VillainTracker, and see that the default villain is displayed both in the controls and as the only row in the table view. Furthermore, if you edit the villain’s name, last seen date, or mugshot in the controls, you should see those new values reflected in the table view. You still can’t edit anything directly in the table view, but let’s change that right now. We’re going to implement one more dataSource method, tableView:setObjectValue:forTableColumn:row:, which will allow the user to edit values directly in the table view, and push the changes down into the model objects. This is basically the inverse of the last method you saw, and is nearly as simple in its implementation:

Here you see that we’re looking up the relevant villain in the same way as before, and this time instead of returning a value, we’re using the column’s identifier to set an attribute of the villain object. We end the method by calling updateDetailViews,

Return Main Page Previous Page Next Page

®Online Book Reader