“data-only” Objective-C对象的更好替代方案是什么?

8

我经常遇到这样的设计选择,有些困难; 我正在寻求其他观点。

我经常想保留列表或传递一些状态块,这些状态块基本上只是一组值。 这些值往往是原始类型:浮点数、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,只能通过一些(有争议的)技巧来使用(在这种情况下将其强制转换为double类型)。

最后,我可以创建仅包含私有成员数据和getter/setter方法的数据容器对象。(这些在Java中被称为“bean”)。与字典相比,这些对象更加简洁易用,更符合Cocoa的结构,但对于我来说感觉过于复杂,尤其是如果我只需要它们作为“内部类”,用于单个对象类型的状态管理。

各位伟大的Cocoa程序员,你们是如何做到这一点的呢?

2个回答

15

根据情况,我通常使用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仍然难以处理,但可以这样做:

myStateObject.foo = [NSNumber numberWithFloat:7.0];

使用这种方法可以大部分减轻疼痛,并让您更好地使用Cocoa集合类来处理数据洗牌。


4
除非你有一些非常注重性能的代码,使用对象会导致问题,否则创建模型类几乎总是可行的。 - Rob Keniger
3
谢谢你的留言,Matt。在这种情况下,你甚至不需要使用NSNumber来封装浮点数--可以使用@property语法来访问基本数据类型。(当然,对于NSTimeInterval也是一样的,它恰好是typedef'd为基本float类型)。 - Ben Zotto

3
并不一定认为这种方法是“最佳”的,但在您的建议之间有一个折中方案:创建C结构以保存信息,然后在需要将它们放入Cocoa数据结构时将结构体包装在NSValue对象中。您可以在UIKit中看到这样做的一些情况,例如在通知中使用像CGPoint这样的结构体(我相信AppKit也是如此)。
有关更多信息,请参见Cocoa的数字和值编程主题中的“使用值”

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接