“仅数据”Objective-C对象的更好替代方案?

时间:2010-02-15 22:31:27

标签: objective-c cocoa design-patterns nsdictionary cocoa-design-patterns

我经常遇到这样的设计选择并且有点挣扎;我正在寻找其他一些观点。

我经常想要保留列表,或者传递基本上只是值集的状态块。值往往是原始类型:浮点数,NSTimeIntervals,CGPoints等。

我的第一个倾向通常是为这些属性集创建C结构,例如

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

但是C结构与本机Cocoa集合类(NSArrayNSSetNSDictionary)不能很好地结合使用,并且使用过多的结构来跟踪大量的状态感觉就像它运行我的Cocoa友好代码的其余部分 - 我最终拥有并直接管理结构数组,并在消息中传递结构指针等。

另一方面,由于原始性能不一定是关键,我可以将这些值编码为NSDictionary,将它们全部包含在NSValueNSNumber中,但结果语法几乎不简洁,并且有点脆弱,在运行时要求插入和查找的类型和名称正确性:

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

和某些类型,如NSTimeInterval,只能与一些(可论证的)hackery一起使用(在这种情况下类型转换为double)。

最后,我可以使用私有成员数据创建仅限数据的容器对象,并且只创建getter / setter。 (这些在Java中被称为“bean”。)这些比字典更容易访问,更多Cocoa而不是结构,但对我来说感觉有点过分,特别是如果我只需要它们作为用于状态管理的“内部类”单个对象类型的内部。

如何,伟大的Cocoa编程公众,这样做?

2 个答案:

答案 0 :(得分:14)

根据具体情况,我使用NSDictionary类运行任意数据,或者我创建容器类(Objective C中的@ property / synthesize标签使这非常简单)。通过使用ObjC作为头文件:

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

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

@end

然后可以在.m文件中使用@synthesize <variable>来自动创建setter / getter。然后,虽然匿名NSNumbers仍然是ornery,你可以这样做:

myStateObject.foo = [NSNumber numberWithFloat:7.0];

这应该可以消除大部分的痛苦,让你使用Cocoa集合类来更好地改变数据。

答案 1 :(得分:2)

不一定认可这种方法是“最好的”,但是你的提议之间存在中间立场:创建C结构来保存信息,然后在需要将它们放入NSValue对象时将结构包装起来Cocoa数据结构。你可以看到UIKit在某些情况下使用CGPoint这样的结构通知(我确信AppKit也可以这样做)。

有关详情,请参阅Number and Value Programming Topics for Cocoa中的“使用值”。