Cocoa:测试以查找NSString是不可变的还是可变的?

Str*_*ion 7 cocoa types objective-c mutable immutability

这会产生一个不可变的字符串对象:

NSString* myStringA = @"A";  //CORRECTED FROM: NSMutableString* myStringA = @"A";
Run Code Online (Sandbox Code Playgroud)

这会产生一个可变的字符串对象:

NSMutableString* myStringB = [NSMutableString stringWithString:@"B"];
Run Code Online (Sandbox Code Playgroud)

但是这两个对象都被报告为同一种对象,"NSCFString":

NSLog(@"myStringA is type: %@, myStringB is type: %@", 
[myStringA class], [myStringB class]);
Run Code Online (Sandbox Code Playgroud)

那么什么是在内部区分这些对象,以及如何测试它,以便我可以轻松地确定一个神秘的字符串变量是不可变的还是可变的,然后再做一些邪恶的事情呢?

Rob*_*ier 13

这些文档包括一个相当长的解释,说明为什么Apple不希望你这样做,以及为什么他们在接收可变对象中明确地不支持它.摘要是:

所以不要根据内省告诉你关于对象的内容来决定对象的可变性.根据您在API边界处传递的内容(即基于返回类型)将对象视为可变对象.如果在将对象传递给客户端时需要明确地将对象标记为可变或不可变,请将该信息作为标志与对象一起传递.

我发现他们的NSView示例最容易理解,它说明了一个基本的Cocoa问题.您有一个名为"elements"的NSMutableArray,您希望将其作为数组公开,但不希望调用者搞砸.你有几个选择:

  1. 将NSMutableArray公开为NSArray.
  2. 请求时始终制作不可变副本
  3. 将元素存储为NSArray,并在每次变异时创建一个新数组.

我已经在各个方面做了所有这些.#1是迄今为止最简单,最快速的解决方案.它也很危险,因为阵列可能会在调用者的背后发生变异.但是Apple表示它们在某些情况下的作用(请注意NSView中的-subviews警告).我可以确认,虽然#2和#3更安全,但它们可能会产生严重的性能问题,这可能就是为什么Apple选择不在像-subviews这样经常访问的成员上使用它们的原因.

所有这一切的结果是,如果你使用#1,那么内省就会误导你.你有一个NSMutableArray强制转换为NSArray,并且内省将表明它是可变的(内省无法知道其他情况).但你不能改变它.只有编译时类型检查可以告诉你,所以这是你唯一可以信赖的东西.

对此的修复将是某种可变数据结构的快速写时复制不可变版本.那样#2可能会以不错的性能完成.我可以想象NSArray集群的更改将允许这样做,但它今天在Cocoa中不存在(并且可能会影响正常情况下的NSArray性能,使其成为非首发).即使我们拥有它,也可能有太多的代码依赖于当前的行为来允许可信性内省被信任.


Phi*_*ert 4

没有(已记录的)方法来确定字符串在运行时是否可变。

您可能期望以下其中一项可行,但它们都不起作用:

[[s class] isKindOfClass:[NSMutableString class]]; // always returns false
[s isMemberOfClass:[NSMutableString class]]; // always returns false
[s respondsToSelector:@selector(appendString)]; // always returns true
Run Code Online (Sandbox Code Playgroud)

更多信息请参见此处,尽管它不能帮助您解决问题:

http://www.cocoabuilder.com/archive/cocoa/111173-mutability.html