jeonatl3 jeonatl3 - 1 month ago 8
Swift Question

Swift - Detecting whether item was inserted into NSMutableSet

This is more for interest rather than a problem, but I have an

NSMutableSet
, retrieved from
UserDefaults
and my objective is to append an item to it and then write it back. I am using an
NSMutableSet
because I only want unique items to be inserted.

The type of object to be inserted is a custom class, I have overrode
hashCode
and
isEqual
.

var stopSet: NSMutableSet = []

if let ud = UserDefaults.standard.object(forKey: "favStops") as? Data {
stopSet = NSKeyedUnarchiver.unarchiveObject(with: ud) as! NSMutableSet
}

stopSet.add(self.theStop!)

let outData = NSKeyedArchiver.archivedData(withRootObject: stopSet)
UserDefaults.standard.set(outData, forKey: "favStops")
NSLog("Saved to UserDefaults")


I get the set, call
mySet.add(obj)
and then write the set back to UserDefaults. Everything seems to work fine and (as far as I can see) there don't appear to be duplicates.

However is it possible to tell whether a call to
mySet.add(obj)
actually caused an item to be written to the set.
mySet.add(obj)
doesn't have a return value and if you use Playgrounds (rather than a project) you get in the output on the right hand side an indication of whether the set was actually changed based on the method call.

I know sets are not meant to store duplicate objects so in theory I should just trust that, but I was just wondering if the set did return a response that you could access - as opposed to just getting the length before the insert and after if I really wanted to know!

Answer Source

Swift has its own native type, Set, so you should use it instead of NSMutableSet.

Set's insert method actually returns a Bool indicating whether the insertion succeeded or not, which you can see in the function signature: mutating func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element)

The following test code showcases this behaviour:

var set = Set<Int>()
let (inserted, element) = set.insert(0)
let (again, newElement) = set.insert(0)

print(inserted,element) //true, 0
print(again,oldElement) //false,0

The second value of the tuple returns the newly inserted element in case the insertion succeeded and the oldElement otherwise. oldElement is not necessarily equal in every aspect to the element you tried to insert. (since for custom types you might define the isEqual method in a way that doesn't compare each property of the type).

You don't need to handle the return value of the insert function, there is no compiler warning if you just write insert like this:

set.insert(1)