I’m having an issue when creating a set copy of a mutable set, and then having containsObject fail for the (new) set copy. For example:
NSString *sameID = @"XYZ";
Then on main thread/sometimes on different thread:
[mutableSet addObject:sameID];
NSLog(@"adding Object: %@", sameID);
Then on a background thread, always after (I've verified with logging that) sameID has been added:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSSet<NSString *> *newSet = self.mutableSet.copy;
if ([newSet containsObject:sameID]) {
// do stuff
}
});
Seen with a breakpoint:
1. po [newSet containsObject:sameID] // returns NO
2. po [self.mutableSet containsObject:sameID] // returns YES
I've tested that there is no additional or hidden whitespace for the sameID string. AFAIK containsObject for sets containing NSString uses isEqual which doesn’t/shouldn't matter if the strings have different pointers, right?
Edit: Some additional information: the NSStrings that are being added to the mutableSet are happening on different threads but always before creating the newSet copy. Creating and checking newSet is being done on a background thread which is why I'm copying mutableSet (and I'm seeing with logging that this is always after having added string(s) to mutableSet). So I see with log statements that the string (sameID) was added to mutableSet, then on a background thread I'm copying mutableSet to be a set and quickly checking that set for the same string (sameID) and it's not there.
Edit2: I've tested the code below and it passes for me, however when I tried implementing the same solution regarding above it still has the same result (mutableSet contains the string yet newSet does not).
import XCTest
import Foundation
class CustomObj: NSObject {
let id: String
init(id: String) { self.id = id }
override func isEqual(_ object: Any?) -> Bool {
if let other = object as? CustomObj {
return self.id == other.id
} else {
return false
}
}
override var hash: Int {
return id.hashValue
}
}
func testSetStrings() {
let set = NSMutableSet(object: CustomObj(id: "String-1"))
let copySet: Set<CustomObj> = set.copy() as! Set<CustomObj>
let customObjForTest = CustomObj(id: "String-1")
XCTAssertTrue(set.contains(customObjForTest), "Does Not Contain")
XCTAssertTrue(copySet.contains(customObjForTest), "Copy Does Not Contain")
}
testSetStrings()