应该“对多” 关系可以建模为属性吗?
阅读了键值编码编程指南、键值观察编程指南和模型对象实现指南,以及阅读了许多通过有关该主题的 StackOverflow 条目并尝试各种建模场景,我觉得我已经很好地掌握了如何对数据进行建模。
我最终对所有属性和一对一关系使用声明的属性,并由私有 ivars 支持。 对于需要私有可写的只读属性,我在 .h
接口声明中使用 readonly
属性,然后使用 readwrite 重新声明该属性
属性。 在类方法内部,我总是使用带有点语法的属性访问器,并且从不直接访问私有 ivars。.m
文件中声明的类扩展中的
然而,有一个方面仍然让我感到困惑:如何正确地建模一对多关系,特别是当集合是公开不可变但私有可变时(即模型对象的使用者不能向集合添加或删除对象,但集合的内容由班级私人管理)。
我确实了解如何实现多对多关系的 KVC 访问器方法(countOf
、objectsIn
等),这是我的路线到目前为止一直在关注。
但是,我看到一些示例代码使用声明的属性来公开关系,没有实现 KVC 访问器方法,但仍然是键值可观察的。 例如:
@interface MyModel : NSObject
{
// Note that the ivar is a mutable array,
// while the property is declared as an immutable array.
@private NSMutableArray *transactions_;
}
@property (nonatomic, retain, readonly) NSArray transactions;
@end
--------------------
@implementation MyModel
@synthesize transactions = transactions_;
- (void)privateMethodThatManagesTransactions
{
[[self mutableArrayValueForKey:@"transactions"] addObject:t];
}
@end
如果消费者对象将自身添加为 "transactions"
键路径的 MyModel
实例的观察者,则每当从该实例添加或删除交易时,它都会收到通知。 transactions
集合(只要突变是通过 mutableArrayValueForKey:
方法完成的)。
对我来说,这似乎是公开多方关系的最干净的方法,因为我不需要手动编码集合 KVC 访问器,并且它可以保持代码干净。
然而,这似乎并不是苹果文档所提倡的方式,我不禁想知道它的工作原理是否只是一个不可靠的副作用。
因此,在我开始从事的项目的现实模型类中采用一种或另一种技术之前,我想获得经验丰富的 Cocoa 开发人员的意见和建议。
所以问题是:如果我使用属性来建模一对多关系,我是否还需要实现 KVC 访问器/修改器方法?
更新
即使我将一对多属性声明为readonly
(如上面的示例所示),外部代码仍然可以调用mutableArrayValueForKey: @"transactions"
在模型对象上并改变集合。 这似乎表明对多关系使用声明的属性并不是正确的方法,但我仍然觉得我不太明白......
After reading the Key-Value Coding Programming Guide, the Key-Value Observing Programming Guide and the Model Object Implementation Guide, as well as reading many StackOverflow entries on the topic and experimenting with various modelling scenarios, I feel like I have a good grasp on how to model my data.
I end up using declared properties for all my attributes and to-one relationships, backed by private ivars. For read-only attributes which need to be privately writeable, I use the readonly
attribute in the .h
interface declaration, then re-declare the property with the readwrite
attribute in a class extension declared in the .m
file. Inside the class methods, I always use the property accessors with the dot syntax and never access the private ivars directly.
There is however one aspect which still leaves me puzzled: how to properly model to-many relationships, especially when the collection is to be publicly immutable, but privately mutable (i.e. consumers of the model object cannot add or remove objects to the collection, but the collection's content is managed privately by the class).
I do understand how to implement the KVC accessor methods for to-many relationships (countOf<Key>
, objectsIn<Key>AtIndex
, etc.) and this is the route I've been following so far.
However, I've seen some sample code that uses declared properties to expose the relationships, do not implement the KVC accessor methods, yet are still Key-Value observable. For example:
@interface MyModel : NSObject
{
// Note that the ivar is a mutable array,
// while the property is declared as an immutable array.
@private NSMutableArray *transactions_;
}
@property (nonatomic, retain, readonly) NSArray transactions;
@end
--------------------
@implementation MyModel
@synthesize transactions = transactions_;
- (void)privateMethodThatManagesTransactions
{
[[self mutableArrayValueForKey:@"transactions"] addObject:t];
}
@end
If a consumer object adds itself as an observer of a MyModel
instance for the "transactions"
key path, it will be notified whenever transactions are added or removed from the transactions
collection (as long as the mutations are done via the mutableArrayValueForKey:
method).
To me, this seems like the cleanest way to expose to-many relationships as I don't need to hand-code the collection KVC accessors and it keeps the code clean.
However, it doesn't seem to be the way that is promoted by the Apple documentation, and I can't help but wonder if the fact that it works is only an unreliable side-effect.
So before commiting to one technique or the other in my real-life model classes for a project I'm beginning to work on, I'd like to get the opinion and advice of experienced Cocoa developers.
So the question is: if I use properties to model to-many relationships, do I still need to implement the KVC accessor/mutator methods?
Update
Even when I declare a to-many property as readonly
, like in the example above, external code can still call mutableArrayValueForKey:@"transactions"
on the model object and mutate the collection. This seems to indicate that using declared properties for to-many relationships isn't the way to go, but I still feel like I don't quite get it...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
是的。
简单:在标头中将属性声明为
readonly
,然后 在实现文件的类扩展中将其重新声明为readwrite, copy
。也有变异的。 有了这些,您就不需要使用
mutableArrayValueForKey:
; 相反,您可以直接使用可变访问器。 您仍然会收到 KVO 通知,因为当某些东西第一次将自身添加为属性的观察者时,KVO 会包装这些方法。我有 我的博客上的访问器选择器格式列表,包括可变访问器。
编辑:
这是养成使用可变访问器并避免使用
mutableArrayValueForKey:
的习惯的一个很好的理由。 如果您每次尝试时收到编译器警告(没有这样的 [public] 方法),您将不会从类外部发送突变消息。尽管有
mutableArrayValueForKey:
的可用性以及有人使用它的风险,但符合 KVO 的属性是这里的解决方案。Yes.
Easy: Declare the property as
readonly
in the header, then redeclare it asreadwrite, copy
in a class extension in the implementation file.There are mutative ones, too. With these, you don't need to use
mutableArrayValueForKey:
; instead, you can use the mutative accessors directly. You'll still get KVO notifications, because KVO wraps those methods the first time something adds itself as an observer for the property.I have a list of the accessor selector formats, including the mutative accessors, on my blog.
Edit:
This is a good reason to make it a habit to use the mutative accessors and avoid
mutableArrayValueForKey:
. You won't send mutation messages from outside the class if you get a compiler warning (no such [public] method) any time you try it.Despite the availability of
mutableArrayValueForKey:
and the risk that someone will use it, KVO-compliant properties are the way to go here.