7

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

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

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

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

等等

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

另一方面,由于原始性能不一定很重要,我可以将这些值编码到一个 NSDictionary 中,将它们全部包装在NSValueor中NSNumber,但生成的语法几乎不简洁,而且有点脆弱,需要在运行时类型和名称正确性插入和查找:

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

并且某些类型,例如 NSTimeInterval,只能与某些(有争议的)hackery 一起使用(在这种情况下类型转换为加倍)。

最后,我可以使用私有成员数据和只有 getter/setter 来创建纯数据容器对象。(这些在 Java 中被称为“bean”。)它们比字典更简洁,Cocoa 比结构更多,但对我来说感觉有点矫枉过正,尤其是当我只需要它们作为用于状态管理的“内部类”时单个对象类型的内部。

你,伟大的 Cocoa 编程公众,是怎么做到的?

4

2 回答 2

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

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

myStateObject.foo = [NSNumber numberWithFloat:7.0];

这应该可以消除大部分痛苦,并让您使用 Cocoa 集合类更好地打乱数据。

于 2010-02-15T22:56:54.153 回答
2

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

有关更多信息,请参阅Cocoa 的数字和值编程主题中的“使用值” 。

于 2010-02-15T23:15:52.863 回答