Learn Objective-C on the Mac - Mark Dalrymple [52]
At this point you should be able to compile and run your app, and see that you can edit the value in the name column in the table view, and see your change register in the dedicated Name control as soon as you press tab or enter.
Now it’s time to implement a delegate method that is called whenever the table view’s selection changes. This lets us notice which row the user has selected, change our villain instance variable to point at the relevant row in the villains array, and redisplay all the other controls to match the new selection. Add this method to the @implementation section in AppController.m:
You’ll see that the meat of this method is wrapped inside an if-clause. That’s necessary, because it’s possible for a table view to tell us that it currently has no selected row at all, which it does by returning -1 from its selectedRow method. Beyond that, you should be able to understand what’s happening in there by now. Compile this to make sure that no errors have crept in, but you don’t need to run it just now: we haven’t added the code for creating or deleting a villain yet, so there’s no use trying to make sense of the table view’s selection (since it can’t really change while the table only has one entry).
Adding and Deleting Villains
Finally, let’s implement the newVillain: and deleteVillain: methods, both of which we provided as “stubs” earlier. The newVillain: method adds a new “empty” villain object to our array of villains, tells the table to reload, and tells the table view which row to select (the last one, since that’s the one we just added).
The only new thing you might see in here is [window endEditingFor:nil], which simply tells the window that it’s time to end whatever other editing behavior the user is currently engaged in, such as typing in a text field. We need to call this method so that the edited value can be “saved” to its underlying villain object, because later in newVillain: we’re going to change the table view’s selection, which would in turn wipe out the values shown in the various controls!
Now you should be able to compile and run your app, and see that the “+” button now actually makes something happen. Furthermore, you should be able to click back and forth between all of the villains in the table view and see the values in the other controls change accordingly.
Next we have the deleteVillain: method, which you see here. We’ve added comments to show the different sections, which will be described after the code.
This method is a bit more complicated than most of the code we’ve shown you in this book so far, so a little additional explanation is in order.
In Section 1, we tell the window to finish up any editing that’s going on, then we grab the index of the table’s currently selected row; that is, the row that’s going to be deleted. Note that we already know which villain is selected, because it’s stored in an instance variable, but having the row index is important for making sure the post-delete selection makes sense (later, in Section 4).
In Section 2, we delete the selected object (pointed at by the villain instance variable) from the villains array, then we tell the table view to reload. Note the method for removing the villain from the array, removeObjectIdenticalTo:. This method makes the NSMutableArray scan itself for the object by comparing its actual memory address with the memory addresses of the objects it contains, so that it only finds and removes exactly the object we pass in. Otherwise, if we had gone with the more commonly used removeObject: method, it would be comparing objects by sending the isEqual: method, which in turn compares values. In that case, any other villain objects we had entered with attributes identical to those of the selected villain would run the risk of being deleted as well.
In Section 3, we make a small adjustment: If the previous selected row index was the last in the array, now that we’ve removed an object from the array,