Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

containsObject: returning NO when isEqual and hash match

I have an NSMutableOrderedSet that I'm adding and removing MTLModels from. The hash and isEqual methods will both return true for two objects, but containsObject will return false.

Sometimes this code works and sometimes it doesn't.

models count: 1
isEqual: 1
hashes equal: 1
containsObject: 0

How is it possible the below code could print out the above?

@property (nonatomic, strong) NSMutableOrderedSet *models;

- (void)remove:(MTLModel *)model {
  NSLog(@"models count: %d", self.models.count);
  MTLModel *modelInSet = (MTLModel *)self.models.firstObject;
  NSLog(@"isEqual: %d", [modelInSet isEqual:model]);
  NSLog(@"hashes equal: %d", modelInSet.hash == model.hash);
  NSLog(@"containsObject: %d", [self.models containsObject:model]);
}

Update:

As a follow-up, this returns YES when the NSMutableOrderedSet returns NO:

[[self.models array] containsObject:model]

Update 2:

If I check if modelInSet is contained in self.models, that also returns NO, even though it's the object returned by firstObject.

like image 614
Ben W Avatar asked Oct 15 '13 05:10

Ben W


1 Answers

You are probably mutating the object after adding it to the set. This is not allowed. The set does not recalculate hashes, so if you mutate the object, it will have a different hash from the one stored by the set. This is why creating a new collection (array in your case) works, i.e. because it recalculates all the hashes.

EDIT: To be clear, you can mutate an object after adding it to the set, but its hash value must not change.

like image 53
fumoboy007 Avatar answered Oct 20 '22 15:10

fumoboy007