There was one other motivation for thinking about all of the Objective-C property stuff: Lazy Initialisation.
Lazy Initialisation is a GoodThing™, especially in the iOS world where memory is tight, and performance isn’t always stellar.
So why the bloody hell didn’t Apple add a lazy attribute to the property system, so that you could do this:
@property (retain, nonatomic, lazy) id foo;
In my world, that would synthesise a getter which performs a lazy initialisation the first time it’s called, by calling a standard method (called fooLazyInit or something similar).
It seems to me that this would be a great boon to iOS developers. To some extent it also gets round the instance variable vs setter problem for the init method - the answer becomes simply not to initialise the property at that point.
All of this stuff has been mulling around in my brain for a while, so I was thinking, would it be possible to add some more property macros to my existing ones, like so:
ECPropertyDeclareLazy(name, type, attribute);
ECPropertySynthesizeLazy(name);
The answer is yes, it’s a bit tricky, but it is possible, and here’s how.
My main consideration was that I didn’t want the macro to have to write all the proper getters and setters, since that would mean losing all of the retain/copy/nonatomic goodness that @property gives us (or recreating it in the macros).
So the trick is to wrap the generated getter with one that checks if the instance variable is nil. If it is, it initialises it directly by calling a special initialiser method. It then just calls on to the generated getter.
The solution I came up with looks like this to use:
@interface MyClass
{
ECPropertyDefineVariable(foo, id);
}
ECPropertyDefineLazy(foo, id, retain, nonatomic);
@end
@implementation MyClass
ECPropertySynthesizeLazy(foo, setFoo, id);
- (id) fooInitLazy
{
return [[[SomeClass alloc] init] autorelease];
}
@end
If you don’t care about backwards compatibility with the old runtime, you can get rid of the ECPropertyDefineVariable bit.
The ECPropertyDefineLazy macro is defined like this:
#define ECPropertyDefineLazy(name, type, ...) \
@property (__VA_ARGS__) type name##Lazy; \
@property (__VA_ARGS__) type name; \
- (type) name##LazyInit
Here we actually declare two properties - one called foo, the other fooLazy. We’re going to let Objective-C synthesise fooLazy for us, so we get the right retain behaviour etc.
We also forward declare our fooLazyInit method here. It’s not strictly necessary, and we don’t actually want anyone calling it, but it allows the actual implementation of the method to appear anywhere in the .m file, which is more convenient.
The ECPropertySynthesizeLazy macro is defined like this:
#define ECPropertySynthesizeLazy(name, setter, type) \
@synthesize name##Lazy = _##name; \
- (type) name { if (!_##name) self.name##Lazy = [self name##LazyInit]; return self.name##Lazy; } \
- (void) setter: (type) value { self.name##Lazy = value; }
We let Objective-C synthesise the fooLazy method, but we ask it to use the foo instance variable. This isn’t strictly necessary (it doesn’t really matter what the variable is called), but it makes it consistent with the other property macros, and means that if you do try to access the instance variable directly it will be there and be called what you were expecting.
We then manually implement the getter and setter for the actual foo property.
The setter just calls on to the synthesised version. Annoyingly we have to pass in the name to use for this, since we can’t automatically turn foo into setFoo as it involves turns “f” into “F” in a macro. We also have to pass in the type of the property to the synthesize macro, since it needs it to declare our getter and setter methods. In an ideal world it could work this out for itself.
The getter checks the instance variable directly to see if it’s nil. If so, it calls fooLazyInit to get a value, and assigns it to the synthesised property. From then on, we just call on to that property to return a value.
To maintain the correct semantics for the property, we assign the result of the fooLazyInit method to the synthesised property using its setter. We could just set the instance variable directly, but that might not be atomic when it was supposed to be.
Assigning to the instance variable directly might also break the retain/assign/copy behaviour, so it’s safer to go through the setter. To stick to the standard naming conventions, fooLazyInit should really autorelease any object that it allocates. This isn’t ideal from an efficiency point of view, but it is cleaner. It allows us to call on to the synthesised setter and have it call retain if it’s supposed to. Bear in mind that fooLazyInit is perfectly allowed to return an existing instance, so this isn’t an irrelevance - we need to be certain that the retain/release semantics of fooLazyInit will always be consistent.
Essentially, the point is that I’ve now got a relatively easy, and totally consistent, way of declaring properties to be lazy initialised.
There is a performance penalty, of course - since we have to check the instance variable.
If used wisely though, that’s weighed against the performance gain achieved by not bothering to initialise properties until they’re needed - which may be never.
It also means that you can clear properties more aggressively in response to low memory situations. You don’t have to worry so much about the consequences when you know that the property will get created again on demand.
These macros are pretty new, and might turn out to be a complete cul-de-sac, but I’m going to give them a go.
If you want to try them out as well, I’ll upload them to github
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…
I’ve been beavering away on Neu, and the result is version 1.0b17, which you can download here.
There are three main changes for this version:
First, I’ve changed the “Create Document…” and “Create and Open Document…” menu items. They are now submenus which contain a “Choose Template…” command, but also contain a list of the actual templates. This allows you to choose a template directly without going through any additional dialogs.
Second, I’ve added these menus to the Neu menu in the Dock, and the small status menu that Neu can optionally show on the top right of the menu bar. This means that you can use these menus instead of the Finder’s Services menu. Since the Services menu is a bit clunky and can’t contain dynamically generated content, this is a Good Thing(tm).
Finally, I’ve added “Protect from accidental Quit” option which changes the Quit menu shortcut to Cmd-Shift-Q instead of Cmd-Q. This makes it harder to accidentally quit Neu, if you want to leave it running all the time.
I discovered that there’s already a piece of software out there called Replicator, so it now has a new name.
In fact, it doesn’t just have a new name, it has a neu name, since the new name is Neu.
Still with me?
Visit the Neu (the application formerly known as Replicator) homepage for more details.
Update:
I forgot to mention that the change of name broke the auto-updating mechanism, so you will need to manually download it again.
Hot on the heels of the previous blog post… it turns out that there was a bit of a major bug in 1.0b14, so 1.0b15 is now out.
If you managed to download 1.0b14, then the automatic update process should get you to 1.0b15.
If not, you can download the new one here.
Visit the Neu (the application formerly known as Replicator) homepage for more details.