NSSet with NSStrings containstObject not return YES when it should

RikardA picture RikardA · Aug 12, 2011 · Viewed 8.3k times · Source

I'm loading a dictionary (list of word, not the class) into a NSSet as NSStrings. I then repeatedly send this set the message -containsObject:someNSString. But it always returns false. I wrote some code to test it:

NSLog(@"Random from dictionary: %@", [dictionary anyObject]);
NSString *test = [NSString stringWithFormat:@"BEMIRED"];
NSLog(@"To match this word: %@", test);
if ([dictionary containsObject:test])
    NSLog(@"YES!");

In the log I get the following:

Random from dictionary: BEMIRED
To match this word: BEMIRED

(I'm missing the "YES!")

When I try using CFShow(dictionary) I can see that it actually contains Strings and that everything. An example:

0 : <CFString 0xc3bd810 [0x1386400]>{contents = "BEMIRED"}
3 : <CFString 0xdf96ef0 [0x1386400]>{contents = "SUBJECTIFIED"}

Can anyone please help me here? Thanks!

Answer

Mike Weller picture Mike Weller · Aug 12, 2011

NSSet uses isEqual: to test for object equality, which NSString overrides to perform a string comparison as you would expect. The follow unit test passes:

- (void)testSetStrings
{
    NSSet *set = [NSSet setWithObject:@"String 1"];

    // I've used the UTF8 initializer to avoid any cleverness from reusing objects
    NSString *string1 = [[[NSString alloc] initWithUTF8String:"String 1"] autorelease];

    // Test the references/pointers are not the same
    STAssertTrue([set anyObject] != string1, nil);

    STAssertTrue([set containsObject:string1], nil);
}

We can see the two strings have different pointer values, but the set still returns YES for the containsObject: call.

So I would guess your strings are not in fact equal. I would check for hidden whitespace or other similar issues.