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, and they simply wrap a UIColor and an Int. I have two implementations one that uses a Swift array as the Dictionary's value type, while the other uses a NSMutableArray as the value type. My objective-C code performs extremely fast, but my Swift code is running egregiously slow. Ideally, I would not like to use an NSMutableArray, and would like to keep it as a Swift array. Reason for this is I am writing an algorithm and performance matters, I have noticed some overhead with objC_msgSend. Can anyone help me optimize my Swift code? Am I doing something wrong or is this just a byproduct of swift treating array's as value types? If it is, I would like to understand why the value type performs so slow in this case, what my options are, and how can this scenario can scale going forward? Below I have posted a code snippet and the resulting benchmarks:
Swift Array Code:
let numColors = colorCount(filter: filter, colorInfoCount: colorInfo.count)
var colorCountsArray: [Int] = [Int]()
var countToColorMap: [Int:[CountedColor]] = [Int:[CountedColor]](minimumCapacity: capacity)
var topColors = [CountedColor]()
var startTime = CACurrentMediaTime()
for (color, colorCount) in colorInfo {
colorCountsArray.append(colorCount)
if countToColorMap[colorCount] != nil {
countToColorMap[colorCount]?.append(CountedColor(color: color, colorCount: colorCount))
} else {
countToColorMap[colorCount] = [CountedColor(color: color, colorCount: colorCount)]
}
}
var endTime = CACurrentMediaTime()
print("Time after mapping: \(endTime - startTime)")
Swift Performance:
Time after mapping: 45.0881789259997
NSMutableArray code:
let numColors = colorCount(filter: filter, colorInfoCount: colorInfo.count)
var colorCountsArray: [Int] = [Int]()
var countToColorMap: [Int:NSMutableArray] = [Int:NSMutableArray](minimumCapacity: capacity)
var topColors = [CountedColor]()
var startTime = CACurrentMediaTime()
for (color, colorCount) in colorInfo {
colorCountsArray.append(colorCount)
if countToColorMap[colorCount] != nil {
countToColorMap[colorCount]?.add(CountedColor(color: color, colorCount: colorCount))
} else {
countToColorMap[colorCount] = NSMutableArray(object: CountedColor(color: color, colorCount: colorCount))
}
}
var endTime = CACurrentMediaTime()
print("Time after mapping: \(endTime - startTime)")
NSMutableArray Performance:
Time after mapping: 0.367132211999888
The colorInfo object is a dictionary mapping UIColor objects to an Integer value representing a count. The code essentially reverse maps this, mapping an integer to a UIColor array (its an array because multiple Colors can have the same count). The colorInfo has 60,000 UIColor, Int key value pairs inside of it.