2

我有一个具有只读属性的对象,我正在尝试为其实现 NSCopying。它有一个名为“subConditions”的 mutableArray(其中包含“SubCondition”对象)。我将其设为只读是因为我希望调用者能够更改数组中的数据,但不能更改数组本身。在编写 -copyWithZone: 方法之前,这非常有效。

在摸索了一下之后,我设法得到了一些似乎有效的东西。我不确定这是否是最佳做法。这是我的 -copyWithZone: 方法的简化版本:

-(id)copyWithZone:(NSZone*)zone
{
    Condition *copy = [[[self class]allocWithZone:zone]init];


 NSArray *copiedArray = [[NSArray alloc]initWithArray:self.subConditions copyItems:YES];
 [copy.subConditions setArray:copiedArray];
 [copiedArray release];

    return copy;
}

这是复制只读 mutableArray 的正确/最佳方法吗?

4

1 回答 1

2

我已将 [可变数组属性] 设为只读,因为我希望调用者能够更改数组中的数据,而不是数组本身。

在对象不知情的情况下改变对象属性的值是不好的。例如,假设对象有一个索引集,通过它可以知道选择了哪些对象;如果另一个对象随后从数组中删除了一些子条件,则集合中的部分或全部索引可能引用错误的对象或根本没有对象,这意味着访问选定的子条件将导致 NSOutOfRangeException。

这是一个坏习惯,解决方法是改用相反的习惯,即永远不要这样做。始终通过告诉所有者进行更改来更改拥有的数组 - 或者,至少,创建自己的数组并应用更改并将其显示给原始数组的所有者。在后一种解决方案中,所有者(条件)可能会清除其索引集并忘记选择,但这仍然比引发异常要好。

将属性的类型从 NSMutableArray 更改为 NSArray 后,上面的代码应该会给出警告,因为只有 NSMutableArrays 会响应setArray:. (代码仍然可以工作,假设subConditions访问器返回可变数组而不是自动释放的副本,但编译器会发出警告。)随着从表中改变数组,问题变成了如何启用 Condition 类来提供具有复制的子条件的复制数组的条件实例的副本,同时不允许其他类执行此操作。

一种解决方案是将新数组直接存储到副本的实例变量中。通常,这也将是不好的 mojo,但在这个特定的上下文中(copyWithZone:,受影响的对象是副本),这是适合的极少数情况之一。使用指向成员的操作符来做到这一点:

copy->subConditions = [[NSMutableArray alloc]initWithArray:self.subConditions copyItems:YES];

另一种解决方案是使用类扩展readwrite在类的实现文件中重新声明属性。(将声明保留readonly在类的头文件中。)然后您可以使用属性访问消息:

copy.subConditions = [[[NSArray alloc]initWithArray:self.subConditions copyItems:YES]autorelease];

除了直接 ivar 访问稍微快一点外,没有什么可推荐的:属性版本创建一个临时数组,并发送访问器消息以使新 Condition 创建该数组的副本。您可能希望首先使用属性访问版本,然后使用 Instruments 分析您的应用程序以确定开销是否对您关心的硬件很重要。

于 2010-06-06T12:20:08.627 回答