类实例变量的 Objective-C 模式?
对于可以被子类“覆盖”的类变量,Objective-C 中的一个很好的模式是什么?
常规类变量通常使用文件本地静态变量以及定义为类方法的公开访问器在 Objective-C 中进行模拟。
然而,与任何类变量一样,这意味着该值在类及其所有子类之间共享。有时,子类只更改其自身的值是很有趣的。当类变量用于配置时,通常会出现这种情况。
这是一个例子:在一些 iOS 应用程序中,我有一个给定的公共抽象超类(注释)的许多对象,它们有许多具体的变体(子类)。所有注释都用标签以图形方式表示,并且标签颜色必须反映其注释的特定类型(子类)。因此,所有 Foo 注释必须具有绿色标签,所有 Bar 注释必须具有蓝色标签。在每个实例中存储标签颜色会很浪费(实际上,这可能是不可能的,因为我有很多对象,并且每个实例共有的实际配置数据远大于单一颜色)。
在运行时,用户可以决定所有 Foo 注释现在都将具有红色标签。等等。
由于在 Objective-C 中,类是实际对象,因此需要将 Foo 标签颜色存储在 Foo 类对象中。但这可能吗?对于这类事情来说,什么是一个好的模式?当然,可以定义某种将类映射到其配置值的全局字典,但这有点难看。
What would be a nice pattern in Objective-C for class variables that can be "overridden" by subclasses?
Regular Class variables are usually simulated in Objective-C using a file-local static variables together with exposed accessors defined as Class methods.
However, this, as any Class variables, means the value is shared between the class and all its subclasses. Sometimes, it's interesting for the subclass to change the value for itself only. This is typically the case when Class variables are used for configuration.
Here is an example: in some iOS App, I have many objects of a given common abstract superclass (Annotation) that come in a number of concrete variations (subclasses). All annotations are represented graphically with a label, and the label color must reflect the specific kind (subclass) of its annotation. So all Foo annotations must have a green label, and all Bar annotations must have a blue label. Storing the label color in each instance would be wasteful (and in reality, perhaps impossible as I have many objects, and actual configuration data - common to each instance - is far larger than a single color).
At runtime, the user could decide that all Foo annotations now will have a red label. And so on.
Since in Objective-C, Classes are actual objects, this calls for storing the Foo label color in the Foo class object. But is that even possible? What would be a good pattern for this kind of things? Of course, it's possible to define some sort of global dictionary mapping the class to its configuration value, but that would be kind of ugly.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
为什么你认为这会很丑?这是一种非常简单的方法,因为您可以使用
[self className]
作为字典中的键。使其持久化也很容易,因为您可以简单地将字典存储在 NSUserDefaults 中(只要它仅包含属性列表对象)。您还可以通过调用superclass
方法让每个类默认为其超类的值,直到找到具有值的类。此实现不提供任何检查来确保您不会越过顶级超类,因此您需要确保该类有一个值以避免无限循环。
如果要存储无法存储在属性列表中的对象,可以使用方法在访问字典时来回转换。下面是访问
labelColor
属性的示例,该属性是一个 UIColor 对象。Why do you think this would be ugly? It is a very simple approach since you can use
[self className]
as the key in the dictionary. It is also easy to make it persistent since you can simply store the dictionary in NSUserDefaults (as long as it contains only property-list objects). You could also have each class default to its superclass's values by calling thesuperclass
method until you find a class with a value.This implementation provides no checking to make sure you don't go over the top superclass, so you will need to ensure that there is a value for that class to avoid an infinite loop.
If you want to store objects which can't be stored in a property list, you can use a method to convert back and forth when you access the dictionary. Here is an example for accessing the
labelColor
property, which is a UIColor object.我在这里的回答可能会有所帮助:
什么是推荐的 iOS 应用程序样式设置方法?
在这种情况下,您的注释仅包含对样式的引用(例如,每种样式只需要一个),以及整个样式的指针大小风格还不错。不管怎样,这篇文章可能会给你一些想法。
更新
你是对的,我不知道你的例子对你的问题的模拟有多密切,我考虑对此发表评论。
对于更通用和可重用的解决方案,如果您的全局数据不平凡(正如您在OP中提到的),我可能只会编写一个线程安全的全局字典。您可以在 +initialize 中填充它,也可以通过引入类方法来延迟填充它。然后您可以向
NSObject
添加一些类别来访问和改变静态数据 - 这样做是为了简化语法。我认为这种方法的好处是您可以在任何程序中重用它(即使它可能看起来很难看或写起来很复杂)。如果锁定太多,那么您可能需要按前缀划分字典,或者创建一个简单的线程安全字典,您的类保存该字典的引用——然后您可以通过 objc 运行时合成一个实例变量来存储它并声明一个实例方法来访问它。类方法仍然必须直接使用全局数据接口。
my answer here may help:
What is the recommended method of styling an iOS app?
in that case, your annotation just holds a reference to a style (e.g. you need only one per style), and the size of a pointer for an entire style is not bad. either way, that post may give you some ideas.
Update
you're right, i didn't know how closely your example modeled your problem and i considered commenting on that.
for a more general and reusable solution, i'd probably just write a threadsafe global dictionary if your global data is nontrivial (as you mentioned in your OP). you could either populate it in
+initialize
or lazily by introducing a class method. then you could add a few categories toNSObject
to access and mutate the static data -- do this for syntactical ease.i suppose the good thing about that approach is that you can reuse it in any program (even though it may appear ugly or complex to write). if that's too much locking, then you may want to divide dictionaries by prefixes or create a simple thread safe dictionary which your class holds a reference to -- you can then synthesize an instance variable via the objc runtime to store it and declare an instance method to access it. the class method would still have to use the global data interface directly.