views:

75

answers:

1

Does anyone know of a way to add additional attribute types to the @property keyword without modifying the compiler? Or can anyone think of another way to genericize getter/setter creation?

Basically, I have a lot of cases in a recent project where it's handy for objects to lazily instantiate their array properties. This is because we have "event" objects that can have a wide variety of collections as properties. Subclassing for particular events is undesirable because many properties are shared, and it would become a usability nightmare.

For example, if I had an object with an array of songs, I'd write a getter like the following:

- (NSMutableArray *)songs {
    if (!songs) {
        songs = [[NSMutableArray alloc] init];
    }

    return songs;
}

Rather than writing dozens of these getters, it would be really nice to get the behavior via...

@property (nonatomic, retain, lazyGetter) NSMutableArray *songs;

Maybe some fancy tricks via #defines or something? Other ideas?

+3  A: 

You can always use macros. Even if you modified the compiler, you would probably still want to do this in @synthesize instead of @property, since there is no need to publish this implementation detail. And with a macro it is easy to use any init method. Unfortunately the macros are not aware of the getter= property attribute.

#define synthesizeLazyGetterWithInit(PROPERTY,TYPE,INIT)\
-(TYPE *) PROPERTY { if ( !PROPERTY ) { PROPERTY=[[TYPE alloc] INIT]; } return PROPERTY; }

#define synthesizeLazyGetter(PROPERTY,TYPE)\
synthesizeLazyGetterWithInit(PROPERTY,TYPE,init)

@implementation MyClass

synthesizeLazyGetter(songs,NSMutableArray)
synthesizeLazyGetterWithInit(other,NSMutableArray,initWithCapacity:0)

@end

Edit:

#define synthesizeLazyGetterOptional(PROPERTY,TYPE,INIT);\
-(TYPE *) PROPERTY:(BOOL)inAllocate { if ( !PROPERTY && inAllocate ) { PROPERTY=[[TYPE alloc] INIT]; } return PROPERTY; }\
-(TYPE *) PROPERTY { return [self PROPERTY:YES]; }\
-(BOOL) PROPERTY##Initialized { return nil != PROPERTY; }
drawnonward
I'll accept this since it's probably as close to an answer as there is for this. My only comment would be that I actually *do* want the user of the class to be aware of the implementation detail. My personal opinion is that it is unexpected behavior for getting a property to allocate and return an empty one (even though Apple does this often). What if I was getting it to see if it existed or something?Anyway, that aside, thanks for your time!
DougW
Thanks. You could add a separate isPropertyInitialized method or an optional lazy getter with a doInitialize argument. I have used both approaches. Either could be added to the synthesize macros.
drawnonward