2010-06-06 27 views
2

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

经过一番摸索之后,我设法得到了一些似乎可行的东西。我不确定这是否是最佳做法。这里是我的-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; 
} 

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

回答

2

我已经使[可变数组属性]只读,因为我想调用者能够更改数组中的数据,但不是数组本身。

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

这是一个坏习惯,解决的办法是切换到逆向习惯,即永远不要这样做。通过告诉它的所有者进行更改 - 或者至少使用所应用的更改创建自己的阵列,并将其显示给原始阵列的所有者,从而更改拥有的阵列。在后一种解决方案中,所有者(条件)可能会消除其索引集并忘记选择,但这还是比引发异常更好。

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

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

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

另一个解决办法是使用class extension的财产重新申报的类的实现文件中readwrite。 (请在类的头文件readonly声明。)然后你可以使用属性访问消息:

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

没有太多推荐了另一种,除了直接伊娃访问速度稍快:该物业版本创建一个临时数组,并发送访问者消息以使新条件创建该数组的副本。您可能首先要使用属性访问版本,然后使用工具来分析您的应用程序,以确定您关心的硬件上的开销是否很重要。

+0

谢谢你非常详尽的解释! – 2010-06-06 13:35:30

+0

“因为只有NSMutableArrays响应setArray:”NSMutableArrays不回应这种事 – user102008 2011-01-20 23:47:27

+1

@ user102008:是的,他们这样做。 http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSMutableArray_Class/Reference/Reference.html%23//apple_ref/occ/instm/NSMutableArray/setArray%3A – 2011-01-21 04:17:17

相关问题