2

对于可以被子类“覆盖”的类变量,Objective-C 中的一个很好的模式是什么?

常规类变量通常在 Objective-C 中使用文件本地静态变量以及定义为类方法的公开访问器来模拟。

但是,与任何 Class 变量一样,这意味着该值在该类及其所有子类之间共享。有时,子类只为自己更改值是很有趣的。这通常是使用类变量进行配置时的情况。

这是一个例子:在一些 iOS 应用程序中,我有许多给定的公共抽象超类(注释)的对象,它们有许多具体的变体(子类)。所有注释都用标签以图形方式表示,标签颜色必须反映其注释的特定种类(子类)。所以所有的Foo注解都必须有一个绿色的标签,所有的Bar注解都必须有一个蓝色的标签。在每个实例中存储标签颜色会很浪费(实际上,可能是不可能的,因为我有很多对象,并且每个实例共有的实际配置数据远大于单一颜色)。

在运行时,用户可以决定现在所有的 Foo 注释都将带有红色标签。等等。

由于在 Objective-C 中,类是实际的对象,这需要将 Foo 标签颜色存储在 Foo 类对象中。但这可能吗?这种事情的好模式是什么?当然,可以定义某种将类映射到其配置值的全局字典,但这有点难看。

4

2 回答 2

1

当然,可以定义某种将类映射到其配置值的全局字典,但这有点难看。

为什么你认为这会很丑?这是一种非常简单的方法,因为您可以将[self className]其用作字典中的键。使其持久化也很容易,因为您可以简单地将字典存储在 NSUserDefaults 中(只要它只包含属性列表对象)。您还可以通过调用该方法让每个类默认为其超类的值,superclass直到找到具有值的类。

+ (id)classConfigurationForKey:(NSString *)key {
    if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
    Class c = [self class];
    id value = nil;
    while(value == nil) {
        NSDictionary *classConfig = [_configurationDict objectForKey:[c className]];
        if(classConfig) {
            value = [classConfig objectForKey:key];
        }
        c = [c superclass];
    }
    return value;
}
+ (void)setClassConfiguration:(id)value forKey:(NSString *)key {
    if(_configurationDict == nil) [self loadConfigurations]; // Gets stored values
    NSMutableDictionary *classConfig = [_configurationDict objectForKey:[self className]];
    if(classConfig == nil) {
        classConfig = [NSMutableDictionary dictionary];
        [_configurationDict setObject:classConfig forKey:[self className]];
    }
    [classConfig setObject:value forKey:key];
}

此实现不提供检查以确保您不会越过顶级超类,因此您需要确保该类有一个值以避免无限循环。

如果要存储无法存储在属性列表中的对象,可以在访问字典时使用一种方法来回转换。这是一个访问labelColor属性的示例,它是一个 UIColor 对象。

+ (UIColor *)classLabelColor {
    NSData *data = [self classConfigurationForKey:@"labelColor"];
    return [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
+ (void)setClassLabelColor:(UIColor *)color {
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:color];
    [self setClassConfiguration:data forKey:@"labelColor"];
}
于 2011-08-23T22:56:11.807 回答
0

我在这里的回答可能会有所帮助:

为 iOS 应用程序设计样式的推荐方法是什么?

在这种情况下,您的注释只包含对样式的引用(例如,每种样式只需要一个),并且整个样式的指针大小也不错。无论哪种方式,该帖子都可能会给您一些想法。

更新

Jean-Denis Muys:这解决了我的问题的示例用例,但不是我的问题本身(模拟类实例变量的模式)。

你是对的,我不知道你的例子对你的问题的建模有多紧密,我考虑过对此发表评论。

对于更通用和可重用的解决方案,如果您的全局数据不重要(正如您在 OP 中提到的那样),我可能只会编写一个线程安全的全局字典。您可以+initialize通过引入类方法来填充或懒惰地填充它。然后你可以添加一些类别来NSObject访问和改变静态数据——这样做是为了便于语法。

我想这种方法的好处是你可以在任何程序中重用它(即使它看起来很难写或写起来很复杂)。如果锁定太多,那么您可能希望将字典按前缀划分或创建一个简单的线程安全字典,您的类包含对它的引用 - 然后您可以通过 objc 运行时合成一个实例变量来存储它并声明一个实例方法访问它。类方法仍然必须直接使用全局数据接口。

于 2011-08-23T22:12:55.323 回答