应该将“to-many”关系建模为属性吗?

时间:2009-06-03 18:50:02

标签: cocoa model key-value-observing key-value-coding

阅读键值编码编程指南键值观察编程指南模型对象实现指南之后在阅读有关该主题的许多StackOverflow条目并尝试各种建模方案时,我觉得我对如何建模数据有很好的把握。

我最终使用所有属性和一对一关系的声明属性,由私有ivars支持。对于需要私有可写的只读属性,我使用readonly接口声明中的.h属性,然后在声明的类扩展中重新声明属性为readwrite的属性在.m文件中。在类方法中,我总是使用带有点语法的属性访问器,并且永远不会直接访问私有的ivars。

然而,有一个方面让我感到困惑:如何正确地建模到多个关系,特别是当集合是公开不可变的,但是私有可变的(即模型对象的消费者不能添加或删除对象集合,但集合的内容由类私人管理。

我确实了解如何为多对多关系(countOf<Key>objectsIn<Key>AtIndex等)实现KVC访问器方法,这是我到目前为止所遵循的路线。

但是,我看到一些示例代码使用声明的属性来公开关系,不实现KVC访问器方法,但仍然是Key-Value可观察的。例如:

@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

如果使用者对象将自身添加为MyModel密钥路径的"transactions"实例的观察者,则只要在transactions集合中添加或删除事务,就会通知它(如只要突变是通过mutableArrayValueForKey:方法完成的。

对我而言,这似乎是揭示多对关系的最简洁方式,因为我不需要手动编写集合KVC访问器并且它保持代码清洁。

然而,它似乎并不是Apple文档推广的方式,我不禁怀疑它是否有效这一事实只是一种不可靠的副作用。

因此,在我开始研究的项目中,在我的现实模型类中提交一种技术或其他技术之前,我想得到有经验的Cocoa开发人员的意见和建议。

所以问题是:如果我使用属性来建模多对关系,我还需要实现KVC访问器/ mutator方法吗?

更新

即使我将to-many属性声明为readonly,就像上面的示例一样,外部代码仍然可以在模型对象上调用mutableArrayValueForKey:@"transactions"并改变集合。这似乎表明,使用声明的属性来实现多种关系并不是一种可行的方式,但我仍然觉得我不太明白......

1 个答案:

答案 0 :(得分:6)

  

然而,有一个方面让我感到困惑:如何正确地模拟多对关系,特别是当集合是公开不可变的,但私下可变的......

简单:在标题中将属性声明为readonly,然后在实现文件中声明redeclare it as readwrite, copy in a class extension

  

我确实了解如何为多对多关系(countOf<Key>objectsIn<Key>AtIndex等)实现KVC访问器方法,这是我到目前为止所遵循的路线。

也有变异的。有了这些,您不需要使用mutableArrayValueForKey:;相反,您可以直接使用mutative访问器。你仍然会得到KVO通知,因为KVO会在第一次将自己添加为属性的观察者时包装这些方法。

我的博客上有a list of the accessor selector formats,包括变异访问者。

编辑:

  

即使我将to-many属性声明为readonly,如上例所示,外部代码仍然可以在模型对象上调用mutableArrayValueForKey:@"transactions"并改变集合。

这是养成使用变异访问器并避免使用mutableArrayValueForKey:的习惯的一个很好的理由。如果您在任何时候遇到编译器警告(没有这样的[公共]方法),您将不会从类外部发送变异消息。

尽管有mutableArrayValueForKey:的可用性以及有人会使用它的风险,但符合KVO标准的属性的方式。