Learn Objective-C on the Mac - Mark Dalrymple [43]
Now that you’ve seen the pattern here, let’s take a bigger step forward, and see how to set values for all the remaining “simple” controls at once. You can either compile and run after each of these to check your work as you go, or if you’re feeling a little lucky, just enter all of them and then compile and run at the end. Add these lines to the end of the updateDetailViews method:
The only complication here is for the evilnessView. The view expects a C integer with which to set its value, but our villain has its evilness value stored as an NSNumber inside a dictionary, so we have the added step of converting the object into a plain old int.
Values in Complex Controls
Of the remaining attributes we’re going to display, two of them are simple values (swornEnemy and primaryMotivation), while the third, powers, is a “compound value;” an array of strings. All of them are being displayed in more complex views than the previous attributes were, so we’ll take a little more time with each of them.
First let’s tackle the swornEnemy attribute, which is displayed in an NSComboBox. A combo box maintains a list of items that we must manually edit if we want to add new values to it. We’ll need to do that any time we’re displaying a villain whose swornEnemy is someone we didn’t anticipate back when we were setting up the combo box in Interface Builder. In the following code, we first check to see if the combo box contains an item matching the name we want to display. If it doesn’t, we add one. After that, we tell the combo box to select the appropriate item. Add this to the end of the updateDetailViews method:
Now compile and run, and you should see that the combo box shows the correct value, in this case “Superman.” You can verify that this will also work for items that aren’t included in the combo box in the nib file by changing the relevant line in the applicationDidFinishLaunching: method to refer to some other superhero name that isn’t present in the nib, then compiling and running again.
Next let’s deal with the primaryMotivation attribute, displayed in a matrix of radio buttons. The NSMatrix class lets us select a single cell by specifying its tag, and because these are radio buttons, the others will be automatically deselected. The first thing we’ll do is define a method that returns an array of strings containing all the motivations we’re considering for our villains. These will be arranged in the same order as the cells in the matrix of checkboxes in the nib file, so that their index values match the tags specified for each cell. This method will be added to the privateMethods category that we created earlier.
There are a few noteworthy things about this new method, each of which may give you some insight into the design patterns and philosophies used throughout Cocoa.
■ This is a class method instead of an instance method (indicated by an initial “+” instead of “-”), so everything that happens in here applies to the whole class, no matter how many instances we may create. This is appropriate in many situations where the method doesn’t deal with anything specific to an instance (for example, instance variables).
■ We are using a locally-defined static variable to point to an object we create. The initial assignment to nil only occurs the first time the method is called. This is identical to the use of static local variables in standard C functions, and lets us define a chunk of code (everything inside the if clause) that will be executed only the first time this method is called.
■ We are following a principle called “lazy loading.” Instead of creating the array when the class is initialized, we only create it the first time it’s needed. That way, in case no one ever calls this method, the array is never created.
At first glance, it may seem like overkill to be following these principles. After all, we’re only going to have one instance of this controller class, so why make it a class method? And we know we’re going to need to initialize