Search

Where does it go, George?

Mark Dalrymple

3 min read

Jun 17, 2012

Where does it go, George?

Today’s topic was suggested by Paul Bruneau – thanks!

In case you’ve lost count, we have three places we can declare instance variables in modern Objective-C:

The first is in the class interface, as it always has been:

@interface BNRThingie : NSObject {
    NSString *_thingie1;
    int _thingie2;
}
@end // BNRThingie

The second is in the class extension:

@interface BNRThingie () {
    NSString *_extensionThingie1;
    int _extensionThingie2;
}
@end // extension

The third is at the start of the class implementation:

@implementation BNRThingie {
    NSString *_implementationThingie1;
    int _implementationThingie2;
}
...
@end // BNRThingie

No matter where you declared your instance variables, you can access them in the class:

- (NSString *) description {
    NSString *desc = [NSString stringWithFormat: @"<%@:%p %@ %d %@ %d %@ %d>",
                               [self class], self,
                               _thingie1, _thingie2,
                               _extensionThingie1, _extensionThingie2,
                               _implementationThingie1, _implementationThingie2];
    return desc;
} // description

This brings up the question: “Where should I put my instance variables?” For the most part, you’ll probably make @properties and use @synthesize to create the backing ivar. (You can read more about that at A Motivaton for ivar decorations) The development version of clang supports auto-synthesis of instance variables, so you won’t even have to do @synthesize.

If you have to support older compilers (such as gcc) you’ll need to put the instance variables in the @interface. Similarly, older versions of Xcode don’t have the debugger support for ivars declared anywhere else but the @interface. If you want to see your ivars in Xcode’s debugger panels, you’d need to put ivars in the @interface. Luckily newer Xcodes don’t have this limitation.

If you have public instance variables, part of your public interface, they’d go into the @interface as well. This probably isn’t a wise design idea, but it might be something you have to do.

If your instance variables are private, purely implementation details, put them into the implementation. It still feels weird to put them there, but I’ve been doing Cocoa long enough that I have some ingrained habits to break:

@implementation SomeThing {
    SomeThingTrackingMode _trackingMode;
    CGPoint _anchorPoint, _dragPoint;
}
- (id) initWithPancake: (void *) waffle {
   ...

You can also put them into the class extension if it feels better to you to consolidate the meta / declaratory stuff in one place.

One thing that’s kind of cool is you can declare instance variables in a class extension, then include that class extension (via another header file) into a subclass implementation. You’ll need to make the class extension instance variables @protected or @public so your subclasses can have access to them. This allows you to keep your public header very clean (no instance variables), and have a secondary header with the class extension that’s used by test code and/or subclasses.

Another thing that’s kind of cool is you can put your IBOutlet decorations on instance variables declared in a class extension or in the implementation, as well as decorations on @properties that live in class extensions. Interface Builder will pick up on the outletitude and let you make connections, but also keep them out of the public header file if they’re just implementation details. They’d look something like this:

@interface SomeThing () {
    IBOutlet NSView *_extensionView;
}
@property (strong) IBOutlet NSView *extensionProperty;
@end // extension

@implementation SomeThing {
    IBOutlet NSView *_implementationView;
}

And would be available in Xcode like this:

Plethora of Outlets

Here are my rules of thumb for ivar location:

  • For older compilers or older Xcodes that don’t fully support non-interface ivars, I put them into the @interface

  • If it’s a public ivar, into @interface it goes (I haven’t actually had to use this rule yet)

  • If it’s a private implementation detail, I put it into the @implementation. Sometimes I put them in the class extension. I haven’t totally Searched My Feelings on this one.

  • If it’s something to be exposed to subclasses or to tests, it goes into a class extension in a separate header file.

Fascinated by the ins and outs of Objective-C? The Advanced Mac Bootcamp covers the language in extensive detail.

Mark Dalrymple

Author Big Nerd Ranch

MarkD is a long-time Unix and Mac developer, having worked at AOL, Google, and several start-ups over the years.  He’s the author of Advanced Mac OS X Programming: The Big Nerd Ranch Guide, over 100 blog posts for Big Nerd Ranch, and an occasional speaker at conferences. Believing in the power of community, he’s a co-founder of CocoaHeads, an international Mac and iPhone meetup, and runs the Pittsburgh PA chapter. In his spare time, he plays orchestral and swing band music.

Speak with a Nerd

Schedule a call today! Our team of Nerds are ready to help

Let's Talk

Related Posts

We are ready to discuss your needs.

Not applicable? Click here to schedule a call.

Stay in Touch WITH Big Nerd Ranch News