On 19 Jun 2014, at 10:57 am, Trygve Inda <[email protected]> wrote:

> The method propertyKeys (below) is used to simplify and shorten the code in
> these classes since I want to encode/decode and (upon dealloc), release all
> the properties.


> -(void)dealloc
> {
>    for (NSString* key in [self propertyKeys])
>        [[self valueForKey:key] release];


This looks pretty smelly.

I can understand your motivation, but I think this could end up being 
problematic if later you want to generalise or subclass your object. If a 
subclass adds to the -propertyKeys, it could find them over-released, because 
the base class has already released them (or else it will need to rely on this 
implementation detail of the base class, which is knowledge it shouldn't 
require). If it overrides any property getter to do something different, 
releasing the result is probably going to be wrong. If you declare any 
properties anywhere to be anything other than 'retain' it's going to be wrong. 
You might argue that you don't intend to subclass or generalise or use any 
properties other than 'retain', and it works as it stands, and that would be 
true, but there is a more generic way that is no more work.

Ideally, your -dealloc method should mirror your -init method, so that you have 
each property set to nil listed individually, just as -init sets each one 
individually. Sure, that's tedious if you have hundreds of properties, but it's 
at least reliable with no nasty surprises. If you are determined to iterate a 
list, then at least use the setter, passing nil, rather than the getter, and 
calling release. (That also allows you to change a property to 'assign' or 
'copy' if necessary without creating a bug).

I ought to mention that I used something very close to your scheme a while ago 
to try and save myself a load of tedious coding to init, archive, dearchive and 
dealloc a whole bunch of properties. At first it seemed like a huge win, but 
I've been regretting and undoing it ever since, because every time I come to 
actually use one of these objects, I find these shortcuts not doing exactly 
what they need to do. Having said that I am subclassing, often in ways I didn't 
originally expect to be doing.

> -(NSArray *)propertyKeys
> {
>    NSMutableArray* propertyKeyArray =
>            [[[NSMutableArray alloc] init] autorelease];

Just as a final comment, why not make this a class method, and cache the array 
in a static? It never changes for a given class, so rebuilding it every time is 
an unnecessary waste of time. OK, that is possibly premature optimisation, but 
this sort of case is something that makes sense to "optimise" by design whether 
it matters or not.

It would probably also be better if this method didn't automatically enumerate 
the properties using property_getName, but built it from explicit string 
literals (even though you then have to list them individually). It means 
properties added by a subclass are exclusively the domain of the subclass, as 
they should be, and that properties that you want to exclude from archiving, 
KVO, etc can be simply omitted from the list as needed.

So my arguments against your approach boil down to problems if you subclass, 
which you will probably say you never intend to do. I thought that I wouldn't 
be subclassing as well :)

A performance related argument: using property getters and setters in 
-initWithCoder: and -encodeWithCoder: can bring with them serious performance 
issues. Might not matter in your case, or in most cases, but it really adds up 
if you have a large and complex object graph. A recent exercise to set ivars 
directly in -initWithCoder: instead of using property setters saw a 100 - 600x 
speed improvement when reading a file for a graph with ~10,000 objects. Just 
sayin'.

--Graham
_______________________________________________

Cocoa-dev mailing list ([email protected])

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to