views:

115

answers:

2

I run into design choices like this often and struggle a bit; I'm looking for some other perspectives.

I often want to keep lists of, or pass around chunks of state that are basically just sets of values. The values tend to be primitive types: floats, NSTimeIntervals, CGPoints, etc.

My first inclination is often to create C structures for these sets of properties, e.g.

typedef struct _STATE {
    float foo;
    NSTimeInterval elapsed;
    CGPoint point;
} STATE;

etc.

But C structures don't play nicely with the native Cocoa collection classes (NSArray, NSSet, NSDictionary), and using overmany of them to track lots of state feels like it runs against the grain of rest of my Cocoa-friendly code-- I end up having and directly managing arrays of structs, and passing struct pointers around in messages, etc.

On the other hand, since raw performance isn't necessarily critical, I could encode these values into a NSDictionary, wrapping them all in NSValue or NSNumber, but the resulting syntax is hardly terse, and a little fragile, requiring type and name correctness at runtime for both the insert and the lookup:

[stateDict setObject:[NSNumber numberWithFloat:foo] forKey:@"bar"];
... 
float something = [[stateDict objectForKey:@"bar"] floatValue];

and some types, like NSTimeInterval, are only able to be used with some (arguable) hackery (typecast to double in that case).

Finally, I could create data-only container objects, with private member data and only getters/setters. (These would be called "beans" in Java.) These are more terse to access than dictionaries, more Cocoa than structs, but feel like overkill to me, especially if I only need them as "inner classes" that are used for state management internal to a single object type.

How do you, great Cocoa programming public, do this?

+10  A: 

Depending on the situation, I run either with using NSDictionary classes for arbitrary data, or I create container classes (the @property/synthesize tags in Objective C make this really easy). By using ObjC for the header file:

@interface StateObject : NSObject {
    NSNumber *foo;
    NSTimeInterval *elapsed;
    CGPoint point;
}

@property (retain) NSNumber *foo;
@property (retain) NSTimeInterval *elapsed;
@property (copy)   CGPoint point;

@end

One can then use @synthesize <variable> in the .m file to automatically create the setters/getters. Then, while anonymous NSNumbers are still ornery, you can do:

myStateObject.foo = [NSNumber numberWithFloat:7.0];

This should take most of the pain away, and let you use the Cocoa collection classes to better shuffle data around.

Matt Erickson
+1. Creating model classes is almost always the way to go unless you have some very performance-critical code where the overhead of using objects will cause problems.
Rob Keniger
Thanks for this Matt. In this scenario, you don't even need to wrap floats with NSNumber-- one can use the @property syntax to access primitive types. (Same goes of course for NSTimeInterval, which happens to be a typedef'd primitive float.)
quixoto
+1  A: 

Not necessarily endorsing this approach as "best", but there is a middle ground between your proposals: create C structs to hold the information, and then wrap the structs in NSValue objects when you need to put them into Cocoa data structures. You can see UIKit do this in some cases with structs like CGPoint in notifications (and I'm sure that AppKit does, as well).

See "Using Values" in Number and Value Programming Topics for Cocoa for more on that.

Sixten Otto