Did you know that you can declare IBOutlets in a class extension? I didn't. Man, I love it when I discover something new.
OK, we all know that we can add an outlet property to our header file as shown below. Then we can draw connections to this outlet in Interface Builder.
@interface MainViewController : UIViewController @property (weak, nonatomic) IBOutlet UIButton *playButton; @end
I always assumed the property had to be publicly declared. After all, it's value is set externally when the nib loads. Unfortunately, except for this initial linking, these properties are really an implementation detail. In general, I don't want external code to start mucking about with my outlets.
And, let's face it, it's far too easy to fall into this trap. After all, I have a label. Why shouldn't I just set the label's text. It's quick, it's simple and it works.
controller.titleLabel.text = @"This is my new title";
There are a couple of problems with this. First, if the view has not loaded, then our label won't exist. We will simply be sending the
sendText: message to
nil--which does nothing. From a more theoretical standpoint, we're also letting external code muck about in what really should be an internal implementation matter. This creates code that is tightly bound and hard to modify or maintain.
A more modular implementation might have a
title property. External code might change that property, but our view controller is responsible for determining how the title is displayed.
So, back to the topic at hand. Class extensions allow us to declare methods and define variables that will be added to our class. Typically they are placed in the
.m file, above the
@implementation block. They are most often used to declare private methods and variables.
Of corse, this comes with the standard Objective-C caveat. Nothing in Objective-C is truly ever private. We can always send any message to any object. However, by removing methods and properties from the header file, we are telling other developers (including our future selves) that those methods and properties are implementation details that could change at any time. They should not be called outside the class itself.
The cool bit is that we can also declare our outlets in our class extension, hiding them away and making them private. However, interface builder can still see them, and we can still draw connections to them. The system will still set them up when the nib loads. It's the best of both worlds.
// the class extension @implementation MainViewController() @property (weak, nonatomic) IBOutlet UIButton *playButton; @end // the class implementation @interface MainViewController @synthesize playButton = _playButton; // boring details skipped @end
I'm not sure exactly when Apple added this feature. However, it works in Xcode 4.3.3, and probably in earlier versions as well. I've already converted on of the projects I'm working on--and I really appreciate the cleaner header files.
Ok, back to work….