【问题标题】:Proper way to copy a readonly NSMutableArray复制只读 NSMutableArray 的正确方法
【发布时间】:2010-06-06 09:38:03
【问题描述】:

我有一个具有只读属性的对象,我正在尝试为其实现 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 的正确/最佳方法吗?

【问题讨论】:

    标签: iphone cocoa nsmutablearray readonly nscopying


    【解决方案1】:

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

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

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

    一旦你将属性的类型从 NSMutableArray 更改为 NSArray,上面的代码应该会给出一个警告,因为只有 NSMutableArrays 会响应setArray:。 (代码仍然工作,假设 subConditions 访问器返回可变数组而不是自动释放的副本,但编译器会给出警告。)问题变成了如何使 Condition 类能够提供 Condition 实例的副本以及复制的子条件的复制数组,同时不允许其他类这样做。

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

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

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

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

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    相关资源
    最近更新 更多