为啥说 NSString 的可变副本等于原始不可变副本?

Posted

技术标签:

【中文标题】为啥说 NSString 的可变副本等于原始不可变副本?【英文标题】:Why a mutable copy of a NSString is said to be equal to the original immutable one?为什么说 NSString 的可变副本等于原始不可变副本? 【发布时间】:2014-01-07 06:08:30 【问题描述】:

假设我有一个 NSString* str1 和 NSMutableString* str2,我将 str2 设为 str1 的可变副本。我调用了以下方法:

-(void)someMethod 
    NSString *str1;
    NSMutableString *str2;
    str1 = @"OK";
    str2 = [str1 mutableCopy];

    if ([str2 isEqual:str1]) 
        NSLog(@"Same!");
    
    else 
        NSLog(@"Not exactly!");
    

    NSLog(@"%@", [[str1 class] description]);
    NSLog(@"%@", [[str2 class] description]);

控制台输出:

2014-01-07 14:03:16.291 LearnFoundation[3739:303] Same!
2014-01-07 14:03:16.293 LearnFoundation[3739:303] __NSCFConstantString
2014-01-07 14:03:16.293 LearnFoundation[3739:303] __NSCFString

所以这里出现了混乱,根据NSStringisEqual 的文档,它是returns a Boolean value that indicates whether the receiver and a given object are equal。那么为什么说可变副本与原来的不可变副本相同呢? 提前致谢!

【问题讨论】:

isEqual 比较的是字符,而不是指针引用,因此它们将相等,直到您改变 str2。另见***.com/questions/3703554/… 【参考方案1】:

有(至少)三个独立的概念都可以被认为是“平等”:

    “身份”(我和其他对象是同一个对象吗?) “平等”(我与其他对象完全一样吗?) “值相等”(我的值是否与其他对象相同?)

对于 ObjC 对象,您使用 == 测试相同的身份,但使用 isEqual: 测试相同的值。没有用于测试精确相等性的一站式方法;一般来说,它并不是很有用。

javascript 中(为了比较),您使用 === 测试相同的身份,使用 == 测试等效值。同样没有直接的方法来测试完全相等。

对于像 int 和 float 这样的按值传递类型,没有身份这样的东西,因为您不能传递特定的实例。但是,如果你眯着眼睛,你可以认为这是不同类型具有相同值的类似情况:

int x = 5;
short y = 5;
if (x == y) 
    ...

虽然在这种情况下它不是子类型关系。

【讨论】:

【参考方案2】:

isEqual 比较两个字符串的内容,而不是它们的类型或标识。内容相等,因此它的评估结果为真。

要比较类型,请尝试:

if([str1 isKindOfClass:[str2 class]])
 
   NSLog(@"same");
else
   NSLog(@"different");

您应该会看到“不同”被记录下来。

【讨论】:

这对于字符串来说可能比较棘手,因为 NSCFString(NSString 的私有子类)可以用于可变字符串和不可变字符串。【参考方案3】:

它们与字符串一样,但是是具有不同地址的不同对象。因此,isEqual 返回YES,但与== 的比较结果为NO

【讨论】:

以上是关于为啥说 NSString 的可变副本等于原始不可变副本?的主要内容,如果未能解决你的问题,请参考以下文章

为什么可变结构“邪恶”?

js 不可变的原始值和可变的对象引用

不可变字符串 NSString与可变字符串 NSMutableString

不可变字符串NSString

iOS Objective-C 深入理解Copy

DDD 中的值对象 - 为啥是不可变的?