【问题标题】:Trying to use copied NSMutableString property causes an exception尝试使用复制的 NSMutableString 属性会导致异常
【发布时间】:2012-08-16 17:49:05
【问题描述】:

我启动了一个小型 Xcode 项目来调查 NSMutableString 属性应该是 copy 还是 retain。我用copy 属性声明了我的属性:

@property (nonatomic,copy) NSMutableString *stringA;

然后将其初始化为self.stringA = [NSMutableString new];

终于尝试设置一个字符串[stringA setString:@"A"];

无论程序给出什么,

“由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'尝试使用setString改变不可变对象:'”

是不是因为结果字符串是NSString?这是否意味着我应该使用retain 属性和NSString 属性使用copy 声明我的NSMutableString 属性?

【问题讨论】:

  • 一开始你几乎肯定不希望可变字符串作为属性;至少,不是作为 API 公开的。
  • 我的回答,用太多的话来说:stackoverflow.com/questions/4995254/…
  • 对 NSStrings 使用 copy 是没有意义的。
  • @HotLicks 不,不是。记住语义!如果客户端将可变字符串作为参数传递给您的类,您保留它,然后他们在您背后改变它,会发生什么?坏事。简单的解决方案是制作一个副本——如果参数是可变的,那么您就有了正确性,并且您可以轻松传递一个字符串,而无需创建更多副本。如果它是不可变的,那么它可以return [self retain] 而无需进行深层复制。
  • 到目前为止我的理解是复制在 NSString 中很重要,但在 NSMutableString 中不重要。由于 NSMutableString 是 NSString 的子类,因此您可以将 NSMutableString 分配给 NSString。如果我在这里错了,请纠正我。

标签: objective-c cocoa nsmutablestring declared-property


【解决方案1】:

你是对的,NSMutableStringcopy 方法返回一个不可变 NSString。这是 Cocoa 中的约定,它也适用于NSMutableArrayNSMutableDictionary 等。

因此,如果您希望您的属性保持可变,您应该将其声明为retain。如果您需要复制语义,但仍希望结果是可变的,则必须为属性实现自己的 setter(并使用 mutableCopy 进行复制)。

您经常看到copy 用于字符串属性的原因是,通常需要保证字符串是不可变的,无论分配给属性的字符串类型如何。否则,您最终可能会意外修改其他地方的相同字符串,这可能很难调试。不可变对象还具有线程安全的优点。

【讨论】:

  • 所以基本上我应该对 NString、NSArray、NSDictionary 类型使用副本,因为存在可变变体,对于像 NSMutableString、NSMutableArray 这样的可变类型,我应该使用保留。这是正确的吗?
【解决方案2】:

我要问的第一个问题是 stringA 是如何初始化的。如果您从普通字符串设置它,那么这可能就是您得到它的原因。复制和保留实际上执行不同,您应该知道为什么要使用其中一种。

Copy 实际上是对内存进行复制,以便您对该属性所做的任何更改都不会影响它设置的原始内容,其中保留只会增加内存的保留计数,因此您可以确保它不会被释放,直到你已经完成了引用它。

【讨论】:

  • 我将它初始化为 self.stringA = [NSMutableString new];
  • 将其初始化为 self.stringA = [[NSMutableString alloc] init];看看它是否改变了什么
  • new 只是alloc init 的简写,它们的作用完全相同。
  • 只保留它可能会像 omz 所说的那样修复它。
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2013-10-27
  • 2013-01-07
  • 2012-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多