I've been writing some iPhone apps recently and have thus been re-exposed to the horror that is Objective-C. I've written plenty of Objective-C over the years, but coming back to it from proper modern languages like Java, C# and Ruby is just painful. It's really showing it's age and I harbour a hope that the macruby work Apple's doing right now is actually going to become the official way to write Mac and even iPhone software over the coming couple of years. That would be just perfect as the underlying Objective-C stuff would still be there for compatibility's sake and performance where necessary. Go on Apple, you know you want to!
Anyway, that mini-rant was not what I came here for. I've been wrestling with the best way to name and use instance variables. Version 1 was to name them in no special way at all, but then you end up with confusion between properties and the underlying variable and also with methods that want to use a parameter with the same sensible name (as is often the case with init methods):
@interface Person : NSObject
{
NSString *name;
}
@property(nonatomic, retain) NSString *name;
@end
@implementation Person
@synthesize name;
// This gives a compiler warning because parameter name masks the instance var.
// Calling the parameter anything else is ridiculous though.
– (id)initWithName:(NSString *)name
{
…
// Need to remember to use self.name rather than name if we want to use the property.
// It's easy to accidentally just assign directly to name and get a messed up retain count.
self.name = name;
….
}
@end
So I've decided it's probably superior to use a prefix for the instance var itself, and though I'd always used m in the past, I'm going for _ here because it seems to be an Objective-C convention:
@interface Person : NSObject
{
NSString *_name;
}
@property(nonatomic, retain) NSString *name;
@end
@implementation Person
// Note that we have to use some extra syntax here to hook up the non-underscored property.
@synthesize name = _name;
// Now the param doesn't clash with anything.
– (id)initWithName:(NSString *)name
{
…
// Property works exactly as before, but direct assignment with _name = name really
// stands out so we're only likely to do it knowingly.
self.name = name;
}
@end
Finally I end up agonising over whether I should always access my instance variables via a property (self.whatever), or whether I'm OK to use them directly (_whatever). Some purists argue that it's worth encapsulating with a property and always using that property. This way you can change your underlying data types but potentially retain the same property methods without breaking the code that uses them – i.e. it's an extra layer of abstraction that protects you from breaking changes. A few years ago I might have bought that, but these days I only add in layers of abstraction when they're truly needed, so I will use the property for external access and the instance var directly for internal access (though I'll always assign to the property to ensure retain counts are correct). I can easily refactor to add in the abstraction if necessary at a later point, but if I don't need it now then I won't bother with it.