Learn Objective-C on the Mac - Mark Dalrymple [45]
That bit of code should be pretty easy for you to grasp by now. First it deselects all the cells, so we start off with a clean slate of “unchecked” checkboxes. Then it goes through each named power from our “master list” of powers, checks to see if our villain’s powers attribute contains a matching string, and if so, sets that cell’s state to NSOnState, which means the checkbox is “checked.” The one new thing to notice here is the special for construct. This is something called fast enumeration, an addition to the latest version of Objective-C that works unlike any form of for in C. It basically takes a collection (typically an NSArray) on the right side of the in, and iterates through it, assigning each object in the collection to the variable specified on the left side of the in, one at a time, then executing the subsequent curly-brace-wrapped code.
Now compile and run your application, and you should see the relevant checkboxes selected in the display: “Intellect” and “Leadership” in the case of Lex Luthor.
Responding to Input
Now that we’re able to display all these villain attributes, it’s time to turn things around and write the code that will let us notice changes the user makes to these fields. You previously created empty action methods which are triggered by the various GUI controls; now it’s time for us to fill up those methods and make them do something useful! Also, we’ll implement a delegate method to let us get the edited value for the one view in our window that doesn’t work with target/action, the NSTextView.
Let’s start off with the NSTextField for displaying and editing the villain’s name, which triggers the takeName: method. Change the method to look like this:
This method starts off by grabbing the string value from the sender, which is the textfield itself, and passing it along to the villain object to set its name. We end up by doing a bit of logging to show all the villain’s current attributes. This can help in debugging, and also serves as a bit of a test for our code at runtime, so we can see that it’s actually doing what it’s supposed to do. The NSLog function takes as its first parameter an NSString used to define an output format, and one additional parameter for each formatting tag (a special sequence starting with a % sign) in the string. This is very similar to the standard printf function in C, with the addition of the %@ tag which prints a description of any Objective-C object. The output from NSLog shows up in Xcode’s
Console window, which normally appears automatically when you launch an application from within Xcode.
TIP: Action methods always pass along a “sender” object, which is normally the object that the user clicked or edited, triggering the method call. If your action method may be triggered by more than one GUI object, you can determine which object it came from by examining sender, comparing it to your instance variables, and so on.
Compile and run your app, and then select the text field containing Lex Luthor’s name. Change the name in some way, press tab (or click on another control in the window), and you should see the output specified in the code printed to the output pane in Xcode. If you don’t see any output window in Xcode when you run your app, switch to Xcode and open the console window by pressing ⌘R. The villain dictionary output is formatted so that you can see each key alongside its associated value. You should be able to find the “name” key and see that its value has changed to the new value you entered.
Most of the rest of our action methods are similar to the takeName: method, and should be self-explanatory. Each of them simply does the inverse of the work we did in the updateDetailViews method, taking values from the GUI and applying them to our model object. Here’s the code for all the “simple” action methods:
Enter all this into VillainTrackerAppDelegate’s main @implementation section, and compile and run your app. You should now be able to edit all the fields we’ve dealt with so far, and