Traditionally with Objective-C, if you wanted to define a property on a class, you did it by
These getter and setter methods followed a simple naming convention - if the property was called foo, they would be called foo and setFoo.
The instance variable could be called anything you liked, since it would only be visible to the outside world via the getter/setter methods, which you wrote. By convention some people called it _foo, or mFoo, or just foo.
Here’s a concrete example.
@interface MyClass
{
id foo;
}
- (id) foo;
- (void) setFoo: (id) value;
@end
@implementation MyClass
- (int) foo { return foo; }
- (void) setFoo: (int) value { /* assign value to foo here, being careful about retain counts */ }
@end
One problem with this approach of course, is that most getters and setters are boilerplate code. The setter can be a bit complicated if the property needed to be retained, or copied, or atomic, so that’s one source of bugs - but essentially they’re the same pattern repeated again and again, which is tedious.
You also have to remember to initialise your property somehow, probably in your init method. This turns out to be slightly subtle. Calling your setter in init is a bit dicey, since a subclass might override it and you’ve no way of knowing if the new version of the setter is safe to run before init has completed. So generally people just perform an assignment to the instance variable here.
And then you must remember to release your property when dealloc is called, if you retained it. You could call your setter here, but again you can’t be sure it’s safe. It’s probably overkill anyway - the setter is likely to zero out the instance variable which is pointless when you’re being deallocated. So generally people just do access the instance variable directly and do something like: [foo release];
Finally, in your code, you have to remember to call the getter/setter, rather than just accessing the instance variable directly. Why? Well, if a subclass overrides your getter & setter to do something fancy, you will break the subclass if you just access the ivar directly.
This can get tricky though - don’t forget that the instance variable can be called the same thing as the getter. It’s easy to write x = foo instead of x = [self foo]. That’s one reason why people might call the instance variable _foo or mFoo instead - just to make it a bit clearer.
Oh, one other thing. Doesn’t it feel a bit like breaking the DRY principal, having to repeat the name of the ivar/property and also repeat the type? Surely this isn’t clever?
So Objective C 2.0 came along and introduced the @property, @synthesize and @dynamic keywords, as a way of taking the leg-work out properties.
Now, you can do this sort of thing:
@interface MyClass
{
id foo;
}
@property (retain) id foo;
@end
@implementation MyClass
@synthesize foo;
@end
Which is really nifty. No more writing boilerplate getters and setters. What’s more, there are some handy attributes like assign,retain,copy,monatomic that you can tag your property with to tailor the generated getter/setter. And you still write your own if you need to.
So that’s all fine and dandy, but there are still some aspects of it that aren’t entirely great. This stuff just writes the getters and setters for you.
It doesn’t actually manage your instance variable. You still need to define a instance variable to store the property in. It can’t help you with your init or dealloc either. You still need to access the instance variable directly for these routines, and you still can’t assume that it’s safe to call the getter or setter.
And there’s still that confusion between the name of the property and the name of the instance variable. Along with the other changes came a new syntax for calling the getter/setter - you can now say object.property instead of [object property]. Still, it’s just as easy to write x = foo instead of x = self.foo.
You can tell @synthesize that you used a different name for the instance variable, but this is a bit of a pain, you have to write things like:
@synthesize foo = _foo;
This just looks ugly, and it feels like it is breaking the DRY principal again.
So along comes a new runtime, and things move forward again a bit.
Now, you don’t actually need to define the instance variable at all, so you can do:
@interface MyClass
@property (retain) id foo;
@end
@implementation MyClass
@synthesize foo;
@end
Now we’re motoring! No more repeating the name and the type in multiple places.
We’ve still got the instance variable though, it’s just generated for us by the compiler. But we can’t get at it unless we declare it ourselves, so I guess we sort of don’t have it, philosophically speaking. Which means that we have to just bite the bullet and call self.foo = blah in our init method, and self.foo = nil in our dealloc method.
Hang on though. Wasn’t that supposed to be bad? Well, uh, yeah, maybe. So does this step forward make it ok?
(tumbleweed passes)
Ok, so this is a bit weird. It seems that the answer is “it’ll be alright, probably”. Just call the setters.
This is kind of good news, but leaves me feeling a bit uneasy.
There’s another problem. If you’re writing shared code, you might not be able to rely on the new runtime, so you might have to declare the instance variable anyway. So now you’ve still got the problem that you can accidentally use it directly.
There’s another more subtle problem. If you used to do foo = [[SomeClass alloc] init] in your init method, and you retain foo generally, that was probably the right thing to do. But if you do self.foo = [[SomeClass alloc] init], that’s probably not the right thing to do if foo is retained. You probably want self.foo = [[[SomeClass alloc] init] autorelease] (which isn’t very efficient), or to call release explicitly afterwards (which is ugly, and easy to forget).
So all of this has me wondering quite what the official way to behave is, right now.
Currently this is what I do:
So, feeling a bit nervous, I started wondering whether I should wrap this stuff in some macros. That way I can change my approach later without having to rewrite all my code.
Yeah, I know, the C preprocessor is the work of the devil - I completely agree - but since this isn’t Dylan we’re working with here and we don’t have a nice clean macro system for defining new syntactic sugar, there’s not much other alternative.
Surely it ought to be possible to do something like:
ECPropertyDeclare(name, type, attributes);
ECPropertySynthesize(name);
ECPropertyInit(name, value);
ECPropertyDealloc(name);
Maybe?
Well, of course, it’s not that simple. One of the main reasons for this is that the whole damn thing is a hack anyway. Objective-C I mean. Really, if you were designing a syntax, you wouldn’t start from here would you?
First problem: the instance variables and the properties have to be declared in different places - separated by the trailing closing brace of the instance variables section. So you can’t define a variable and a property with one macro. Arse.
So we need another macro: ECDeclarePropertyVariable(name, type). So much for the DRY principal.
Still, I’ve actually implemented this, and it sort of works.
I say sort of, because there are two more stumbling blocks.
Second problem: XCode doesn’t apply the preprocessor when parsing the code for its fancy popup menus and whatnot, so it doesn’t really know that your properties are properties anymore. Not great, but not a killer.
Third problem: Interface Builder has no bloody idea at all about the macros. You can put IBOutlet into the macro, or as part of the type passed to a macro, or next to a macro, and it makes no difference. Interface Builder scans the text file, it doesn’t run the preprocessor.
This is a major pain in the arse. There is a workaround, but it’s a bit crap. Essentially you need to repeat the definition of the properties just for IB’s benefit, like this:
#ifndef ECPropertyDefine
@property () IBOutlet id foo;
#endif
The compiler will ignore this, but IB won’t, so it’ll work out that you’ve got some outlets. It doesn’t really care about the property attributes, so you can omit them, but you still have to repeat the type of the property. Another nail in the coffin of the DRY principal.
Apart from all that though, you can sort of get away with this. Whether it’s any better than just doing it all by hand, I’m really not sure. The jury is still out. One thing though - if I do decide to rip them out, it’s going to be a lot easier to use a regular expression to expand my macros out of existence than it would be to rewrite any hand-written property code, which might well be less consistent.
Here are the basic macro definitions:
#define ECPropertyDefineVariable(name, type) type _##name
#define ECPropertyDefine(name, type, ...) @property (__VA_ARGS__) type name
#define ECPropertySynthesize(name) @synthesize name = _##name
#define ECPropertyVariable(name) _##name
#define ECPropertyDealloc(name) [_##name release]
#define ECPropertyInit(name, value) _##name = value
They use _foo for the instance variable. I’d prefer mFoo myself, but that’s impossible. Why? Because it would involve capitalising the first letter of the name of the variable in a macro. Arse.
Coming next… the real reason I did all of this…. Lazy Properties…