NSSet with NSStrings containstObject not return YES when it should
Asked Answered
B

3

13

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!

Beneficence answered 12/8, 2011 at 8:29 Comment(11)
BEMIRED was supposed to be bolded. It doesnt actually show the ** before and after in the log. Sorry, my first time posting here.Beneficence
Can you show us how dictionary is created?Appreciable
Maybe a stupid suggestion, but have you tried [[dictionary allValues] containsObject:...]?Bawcock
I'm using Dave DeLongs DDFileReader: #3707927Beneficence
@Fabian I haven't but it's cruicial that i don't have to use an array when searching since that severly slows down execution. Maybe you meant it as a test? I'll try it.Beneficence
I made some changes to how i load the dictionary, now it's working. Sorry for bothering you with irrelevant question.Beneficence
It’s not an irrelevant question, are you able to to explain the problem in an answer? It could be interesting for us.Illinium
@RikardA: please write an answer that explains how you fixed the problem.Dray
And please post your solution as an answer (you may even accept it).Baseburner
@Dray and DarkDust: I will as soon as I'm allowed to but since I'm a new member it will be another 6 hours. :)Beneficence
This is a preview:Ok so I solved the problem and it had nothing to do with the containsObject method. As I commented i used Dave DeLongs DDFileReader. So by using CFShow on the entire dictionary I noticed that every word had a new line at the end of it. So instead of the -readLine method i used the -readTrimmedLine (bot methods in above mentioned file reader). This solved the problem for me. For future forum visitors I'd like to draw attention to the discussion DarkDust and zoul had about -containsObject and -member (both methods of NSSet) which it turns out both uses the -isEqual method.Beneficence
D
28

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.

Demetricedemetris answered 12/8, 2011 at 10:17 Comment(0)
B
0

The -[NSSet containsObject:] seems to check for the pointer value only (the documentation is very lacking for that method), not for object equality. So you need to use -[NSSet member:] instead, which uses isEqual: to check whether an object that is considered to be equal is in your set.

if ([dictionary member:test])
    NSLog(@"YES!");

Edit: Actually it seems that containsObject: does use isEqual: as well. They only seem to differ in what they return (containsObject: returns a BOOL while member: returns id). I'm letting this answer stay for documentation purposes.

Baseburner answered 12/8, 2011 at 8:36 Comment(3)
This is crazy, have you some pointers to explain the behaviour? Did you test it? According to this Cocoa Builder thread containsObject: should use object equality just as expected.Illinium
It doesn't seem to work there either. I'm starting to think it's a problem with the way i'm reading the file.Beneficence
@zoul: You're right. Given the fact that nothing specific is mentioned in the documentation for containsObject:, but member: specifically says it's using isEqual:, I was assuming that containsObject: would simply check for the pointer value which would be pretty fast. I searched for a confirmation, but other than the thread you're quoting (which says I was wrong) I couldn't find anything.Baseburner
B
0

Ok so I solved the problem and it had nothing to do with the containsObject method. As I commented i used Dave DeLongs DDFileReader found here: Dave DeLongs DDFileReader

So by using CFShow on the entire dictionary I noticed that every word had a new line at the end of it. So instead of the -readLine method i used the -readTrimmedLine (bot methods in above mentioned file reader). This solved the problem for me.

For future forum visitors I'd like to draw attention to the discussion DarkDust and zoul had about -containsObject and -member (both methods of NSSet) which it turns out both uses the -isEqual method.

Beneficence answered 15/8, 2011 at 18:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.