Learn Objective-C on the Mac - Mark Dalrymple [31]
NOTE: This business of property-izing instance variables, a new feature in Objective-C 2.0, is a pretty nice way of dealing with instance variables that are likely to change while the application is running. If you choose to @synthesize the getters and setters like we just did, then you know that you’re accessing your instance variables in a way that is standardized and future-proof.
Now would be a good time to press the Build button in Xcode and make sure you haven’t made any errors so far. If you’ve entered everything correctly, your application should compile without any warnings or errors. If not, take a look at the error messages displayed by Xcode, and try to fix the problems they refer to. In general, compiling Objective-C is a lot faster than compiling C++ or Java code, so you don’t have much to lose by compiling frequently. During the rest of this chapter, we’ll be asking you to frequently compile your app and then run it, so we can make sure that each feature we code actually works as intended before going on to the next.
Planning for the GUI
Soon we’ll get started with laying out our GUI. Before we get to that however, let’s add the outlets and actions for each of our GUI controls to our controller class. Remember, an outlet is nothing more than a specially-marked instance variable, and an action is simply any method that matches a specific signature, taking a single parameter of type id and returning void. Note that in source code, the return type for an action is typically marked as IBAction instead of void. IBAction is actually defined to be the same as void, so as far as the compiler’s concerned it makes no difference. This is done only to provide a “hint” to Interface Builder, so that it knows which methods are meant to be action methods. Now, let’s say we have some sort of design document that specifies several villain attributes and their types. Based on their types and usages, we could map each attribute to a suitable GUI class. See Table 4-1.
Table 4-1. Villain Attributes Mapped to GUI Classes
Based on this specification, we’ll add one outlet and one action for each GUI control. The outlet will let us access the control to set and retrieve its value whenever necessary, and each control will call the appropriate action method to inform us when its contents have changed. Now modify the controller class’s interface (in VillainTrackerAppDelegate.h), adding all the lines shown in bold here:
You may notice that one thing seems to be missing here: there is no action method defined for the NSTextView used for editing our notes attribute. The reason for this is that NSTextView doesn’t actually work with the target/action paradigm. Instead, it informs its delegate when changes are made to its content. We’ll implement that delegate call later, when we also implement all these action methods.
You may also wonder why we didn’t declare these outlets to be properties of our VillainTrackerAppDelegate class, as we did for the villain instance variable. One of the biggest reasons for using properties is to properly handle instance variables that change at run-time, by ensuring that the getters and setters in a object are correctly implemented using the @synthesize keyword. The outlets that point to our GUI controls will not change after the nib file is loaded, so there’s no point going through the motions of making those into properties as well.
Later we’ll implement each of the action methods to make their callers’ changes propagate back to our villain object. For now, just for the sake of having a compilable application, we’ll just put in some empty method implementations,