【问题标题】:Why does NSString sometimes work with the equal sign? [duplicate]为什么 NSString 有时与等号一起使用? [复制]
【发布时间】:2012-02-06 00:04:24
【问题描述】:

可能重复:
Understanding NSString comparison in Objective-C

刚刚阅读有关平等与身份的内容,我意识到在比较我的 objc 代码中的字符串时,我一直在使用一些等号。奇怪的是它实际上有时会起作用,我想知道为什么。

http://www.karlkraft.com/index.php/2008/01/07/equality-vs-identity/

我有两段代码,一段有效,另一段无效。

工作。在这里,我有一个名为“Category”的对象,它有一个名为“name”的 NSString 属性。

@property (nonatomic, retain) NSString *name;

然后我有一个函数,我在其中传递一个“类别”指针,当我在这里使用等号时,它工作得很好。

 -(void)addCategoryToStorage:(Category*)newcategory {
      if(newcategory.name != @"All") {  // this works

不工作。这里我使用 NSFileManager 调用的输出;

NSArray *dirContent = [self.fileManager 
                       contentsOfDirectoryAtPath:@"MyFiles"
                       error:nil];

然后我尝试比较数组中的 NSStrings:

for(int i = 0; i < [dirContent count]; i++) { 
    if([dirContent objectAtIndex:i] == @"MyFile") // This will never be True

所以我的问题是,这两个 NSString 指针工作方式如此不同的原因是什么?我知道我不应该使用“==”,但目前,但我很好奇为什么它有时会起作用。

我注意到它们在调试时有些不同。在第一种情况下,“newcategory”的“名称”表示 (__NSCFConstantString*) 并且值可见。 出于某种原因,“dirContent”数组包含两个 (__NSString*) 对象,其中的值不可见。

这引发了另一个问题。是什么让第一种情况下的 NSString 成为常量?当我将它传递给函数时,它似乎与它的创建方式有关。当我分配一个具有 NSString 属性的新对象,然后将其传递给函数时,该函数将其视为一个常量(对象的 NSString 属性)。但是,当对象存储在列表中并且我通过将 [array objectAtIndex:index] 传递给函数来获取它时,函数不会将其作为常量(即对象的 NSString 属性)来获取。

谢谢!

【问题讨论】:

    标签: objective-c string nsstring identity equality


    【解决方案1】:

    当指针指向同一个对象时,它可能会起作用。

    如果你的代码中有一个字符串字面量,它实际上是一个NSString 类型的静态分配对象。在代码中的任何时候,如果您要引用此字符串值,您实际上使用的是同一个指针。 (指针基本上就是一个内存地址)

    如果您的代码中不止一处有字符串文字@"abc",编译器只会放入一个实例,并使用指向该单个实例的指针。

    这就解释了为什么@"abc" == @"abc"

    以你为例:

    if(newcategory.name != @"All")
    

    只有在您的代码中的某个时刻您这样做时才会起作用:

    newcategory.name = @"All";
    

    如果你愿意,不会工作:

    newcategory.name = [NSString stringWithFormat:@"%c%c%c",'A','l','l'];
    

    因为在最后一种情况下,您明确分配了一个新字符串。

    edit刚刚测试过,这个例子有缺陷:

    newcategory.name = [NSString stringWithString:@"All"];
    

    因为这是优化的,所以您拥有指向@"All"的相同指针

    【讨论】:

    • 技术术语是字符串实习
    • 所以编译器不会在 [NSString stringWithString:@"All"] 和 @"All" 之间产生任何区别?
    • 在某些情况下编译器将字符串变成常量的方式又如何呢?我有两个函数,我为它提供了一个类别指针,有时 NSString 是一个常量。
    • @chikuba:字符串文字将是常量字符串实例(在编译时已经知道等),而其他字符串实例将动态创建。至于+stringWithString:,如果参数是常量字符串,则不必实际复制/克隆。但是,不能保证字符串实习或那些复制优化等。
    • @chikuba:我不确定这些事情。您正在涉足未记录的区域(afaik),这意味着行为可能取决于编译器/运行时版本。一般规则是,如果您实际上是在测试指针是否引用同一个对象,那么您应该只使用== 进行指针比较。通常,您不应该这样做。顺便说一句,这可能很有用。 (例如,从 Core Data 获得的 NSManagedObject 实例保证在数据存储中的每个对象出现一次,因此比较指针而不是调用 -isEqual: 是安全的)
    【解决方案2】:

    如果您想比较两个指针以查看它们是否引用完全相同的对象,NString 总是与“==”符号一起使用。

    而短文字通常以这样一种方式汇集,可能@"ABC" == @"ABC",即使其中一个文字属于不同的类。

    但不要指望它。

    【讨论】:

    • 我知道这一点。 Atm 我想知道我的两个 NSString 之间最大的区别是什么,以及为什么编译器在某些情况下将我的对象属性字符串转换为 const。
    • 有些谜团最好不为人知。 ;) (实际上,我并不了解所有细节,但在 Objective-C 中,像 NSString 这样的对象可以是几个不同的底层类之一,具体取决于它的创建方式。不过,这并不重要,因为NSString 是始终 常量,它会正确响应所有适当的方法/选择器,而不管其底层类如何。)
    【解决方案3】:

    当您与== 比较时,您不是在比较字符串本身,而是在比较指向字符串的指针的值。当您在代码中声明字符串文字时,它们将存储在可执行文件的 data segment 中。如果多个字符串变量指向同一个字符串字面量,它们可能指向同一个内存位置。

    从文件加载字符串时,指针不可能相等,因为它们不可能来自可执行文件的数据段。

    例如,两个字符串文字asdf 通常只会在可执行文件中存储一次,因此指针的值将相等。虽然这是由编译器执行的优化,但并不总是有效。

    NSString* someVariable = @"asdf";
    
    if(someVariable == @"asdf")
       NSLog(@"They are equal!");
    

    【讨论】:

      猜你喜欢
      • 2021-01-30
      • 1970-01-01
      • 2019-04-08
      • 2017-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-27
      相关资源
      最近更新 更多