Cocoa:测试 NSString 是不可变还是可变?
这会产生一个不可变的字符串对象:
NSString* myStringA = @"A"; //CORRECTED FROM: NSMutableString* myStringA = @"A";
这会产生一个可变的字符串对象:
NSMutableString* myStringB = [NSMutableString stringWithString:@"B"];
但是这两个对象都被报告为同一类型的对象,“NSCFString”:
NSLog(@"myStringA is type: %@, myStringB is type: %@",
[myStringA class], [myStringB class]);
那么,这些对象在内部有何区别,以及如何测试这一点,以便我可以在对神秘字符串变量做坏事之前轻松确定它是不可变的还是可变的?
This produces an immutable string object:
NSString* myStringA = @"A"; //CORRECTED FROM: NSMutableString* myStringA = @"A";
This produces a mutable string object:
NSMutableString* myStringB = [NSMutableString stringWithString:@"B"];
But both objects are reported as the same kind of object, "NSCFString":
NSLog(@"myStringA is type: %@, myStringB is type: %@",
[myStringA class], [myStringB class]);
So what is distinguishing these objects internally, and how do I test for that, so that I can easily determine if a mystery string variable is immutable or mutable before doing something evil to it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这些文档包含相当长的解释,说明为什么 Apple 不希望您这样做以及为什么他们明确不支持它 接收可变对象。总结是:
我发现他们的 NSView 示例最容易理解,它说明了一个基本的 Cocoa 问题。您有一个名为“elements”的 NSMutableArray,您希望将其公开为数组,但不希望调用者弄乱。您有多种选择:
我已经在不同的时间点完成了所有这些工作。 #1 是迄今为止最简单、最快的解决方案。这也很危险,因为数组可能会在调用者背后发生变异。但苹果表示这就是他们在某些情况下所做的(请注意 -subviews 在 NSView 中)。我可以确认,虽然 #2 和 #3 更安全,但它们可能会造成重大性能问题,这可能就是 Apple 选择不在经常访问的成员(例如 -subviews)上使用它们的原因。
所有这一切的结果是,如果你使用#1,那么内省会误导你。你有一个 NSMutableArray 转换为 NSArray,内省将表明它是可变的(内省无法知道其他情况)。但你不能改变它。只有编译时类型检查才能告诉您这一点,因此这是您唯一可以信任的事情。
解决这个问题的方法是使用可变数据结构的某种快速写时复制不可变版本。这样#2 就可能以不错的性能完成。我可以想象对 NSArray 集群的更改将允许这种情况,但它在今天的 Cocoa 中不存在(并且可能会影响正常情况下的 NSArray 性能,使其无法启动)。即使我们拥有它,也可能有太多依赖于当前行为的代码,以至于无法信任可变性内省。
The docs include a fairly long explanation on why Apple doesn't want you to do this and why they explicitly do not support it in Receiving Mutable Objects. The summary is:
I find their NSView example the easiest to understand, and it illustrates a basic Cocoa problem. You have an NSMutableArray called "elements" that you want to expose as an array, but don't want callers to mess with. You have several options:
I've done all of these at various points. #1 is by far the simplest and fastest solution. It's also dangerous, since the array might mutate behind the caller's back. But Apple indicates it's what they do in some cases (note the warning for -subviews in NSView). I can confirm that while #2 and #3 are much safer, they can create major performance problems, which is probably why Apple has chosen not to use them on oft-accessed members like -subviews.
The upshot of all of this is that if you use #1, then introspection will mislead you. You have an NSMutableArray cast as an NSArray, and introspection will indicate that it's mutable (introspection has no way to know otherwise). But you must not mutate it. Only the compile-time type check can tell you that, and so it's the only thing you can trust.
The fix for this would be some kind of fast copy-on-write immutable version of a mutable data structure. That way #2 could possibly be done with decent performance. I can imagine changes to the NSArray cluster that would allow this, but it doesn't exist in Cocoa today (and could impact NSArray performance in the normal case, making it a non-starter). Even if we had it, there's probably too much code out there that relies on the current behavior to ever allow mutability introspection to be trusted.
没有(已记录的)方法来确定字符串在运行时是否可变。
您可能期望以下其中一项可以工作,但它们都不起作用:
此处提供更多信息,尽管它不能帮助您解决问题:
http://www.cocoabuilder.com/archive/cocoa/111173-mutability.html
There's no (documented) way to determine if a string is mutable at runtime or not.
You would expect one of the following would work, but none of them work:
More info here, although it doesn't help you with the problem:
http://www.cocoabuilder.com/archive/cocoa/111173-mutability.html
如果您想检查调试目的,以下代码应该可以工作。不可变对象的复制是其本身,而它是可变类型的真正复制,这就是代码所基于的。请注意,由于它调用
copy
它很慢,但对于调试来说应该没问题。如果您想检查除调试之外的任何其他原因,请参阅 Rob 答案(然后忘记它)。免责声明:当然,不能保证对于不可变类型,复制与保留等效。您可以确定,如果
isMutable
返回 NO,则它不是可变的,因此该函数应该命名为canBeMutable
。然而,在现实世界中,一个非常安全的假设是不可变类型(NSString,NSArray)将实现这种优化。有很多代码,包括像 NSDictionary 这样需要从不可变类型快速复制的基本内容。If you want to check for debugging purposes the following code should work. Copy on immutable object is itself, while it's a true copy for mutable types, that's what the code is based on. Note that since it's calling
copy
it's slow, but should be fine for debugging. If you'd like to check for any other reasons than debugging see Rob answer (and forget about it).Disclaimer: of course there is no guarantee that copy is equivalent with retain for immutable types. You can be sure that if
isMutable
returns NO then it's not mutable so the function should be probably namedcanBeMutable
. In the real world however, it's a pretty safe assumption that immutable types (NSString,NSArray) will implement this optimization. There is a lot of code out including basic things like NSDictionary that expects fast copy from immutable types.