Does NSSet's containsObject: test for pointer equality or value equality?
Asked Answered
A

1

30

Say I have an NSSet with a string in it. If I send containsObject: with another string which is a different pointer but the exact same string value, will that return YES?

Also, is it the same story when it comes to removeObject:? I.e., different objects with different pointers but the same string values will cause removal?

Armyn answered 7/12, 2011 at 5:0 Comment(3)
Did you try it? Do you have any reason to believe that it wouldn't?Crassulaceous
If it considered that two strings with the same content were the same object, you could not get the second string into the set so the removeObject: part of the question is moot. NSSet claims to provide "static sets of distinct objects" - not "static sets of non-equal objects".Marlonmarlow
Yes this works. Can confirm containsObject tests for equal strings. I used it to optimize core data updates so I don't have to look up an entity every time to see if it exists. I just use my key field which is a string.Vanadinite
H
40

-containsObject: uses -isEqual: (and -hash) for equality testing. This applies to -removeObject: as well, and any other operations in NSSet that depend on some notion of equality.

Harpp answered 7/12, 2011 at 5:20 Comment(10)
Where is this documented? From what I can see, CFSet is clear that it uses POINTER equality by default, but I don't see NSSet clarifying what it uses?Marlonmarlow
@user: The -[NSSet member:] documentation says that it uses isEqual:; member is one of the fundamental set methods, and it seems to be implied (though, you're right, not explicit) that containsObject: uses member.Crassulaceous
@user256413: All NSSet method that rely on equality must, by definition, use the same equality test. CFSet will use the pointer equality if you don't specify another equality function. If you use kCFTypeSetCallBacks then it uses CFEqual() as the equality comparison.Harpp
Thanks, i was hoping that it used isEqual. Thanks for clearing that upArmyn
Can someone please explain this (apologies for the formatting): NSMutableString *str = [NSMutableString stringWithString:@"Hello"]; NSSet *set = [NSSet setWithObject:str]; NSLog(@"%d", [set containsObject:str]); // returns 1 [str appendString:@"BLA"]; NSLog(@"%d", [set containsObject:str]); // returns 0 NSLog(@"%d", [set.allObjects containsObject:str]); // returns 1Naaman
@jowie: NSSet is a hash table. -[NSMutableString hash] depends on the contents of the string. Mutating the string when it's in the set is explicitly unsupported (same as mutating it when it's in an NSDictionary), because that changes the hash, which makes lookup fail. However, set.allObjects produces an NSArray which does not use hash.Harpp
Interesting that it changes the hash. Why does it do that?Naaman
@jowie: Because the alternative is for every single NSMutableString to have the same hash, which would produce absolutely abysmal performance when stored in dictionaries/sets. The simple rule is you're not supposed to mutate an object that's been placed into an NSSet or used as the key for an NSDictionary.Harpp
So would it be a correct analogy to say that an NSSet is like a key-only NSDictionary (in the same way that an NSArray is a bit like a value-only NSDictionary)? Because NSSet items are unique, a bit like NSDictionary keys?Naaman
@jowie: An NSSet is effectively an NSDictionary that has no value, that's correct. But no, an NSArray is nothing like a value-only NSDictionary (besides all the performance differences, NSDictionarys are unsorted and NSArrays are sorted).Harpp

© 2022 - 2024 — McMap. All rights reserved.