I am trying to build a data structure in Swift that maps an Integer to an array of objects (a dictionary with int as key and array as value). The objects are extremely small
Copy on write is a tricky thing, and you need to think carefully about how many things are sharing a structure that you're trying to modify. The culprit is here.
countToColorMap[colorCount]?.append(CountedColor(color: color as! UIColor, colorCount: colorCount))
This is generating a temporary value that is modified and put back into the dictionary. Since two "things" are looking at the same underlying data structure (the dictionary, and append), it forces a copy-on-write.
The secret to fixing this is to make sure that there's only one copy when you modify it. How? Take it out of the dictionary. Replace this:
if countToColorMap[colorCount] != nil {
countToColorMap[colorCount]?.append(CountedColor(color: color as! UIColor, colorCount: colorCount))
} else {
countToColorMap[colorCount] = [CountedColor(color: color as! UIColor, colorCount: colorCount)]
}
which has a runtime of:
Elapsed Time: 74.2517465990022
53217
with this:
var countForColor = countToColorMap.removeValue(forKey: colorCount) ?? []
countForColor.append(CountedColor(color: color as! UIColor, colorCount: colorCount))
countToColorMap[colorCount] = countForColor
which has a runtime of:
Elapsed Time: 0.370953808000195
53217