Under some conditions, string interpolation produces a string that is way slower to use as a dictionary key than a string produced with String(format:)
. Take the following code:
var map = [String: String]()
let start = Date()
for _ in 0..<100000 {
var s = "asdf"
s = (s as NSString).appendingPathComponent("")
s = transform(s)
s = (s as NSString).substring(from: 1)
map[s] = s
}
print(-start.timeIntervalSinceNow)
func transform(_ s: String) -> String {
return "\(s)/\(s)"
// return String(format: "%@/%@", s, s)
}
On my Mac I get the time interval 0.69 seconds printed out in the console (when using the string interpolation), but when commenting out line 13 and uncommenting line 14 (so that we use String(format:)
) I get a 0.33 seconds time interval, less than half the time. Curiously, whenever uncommenting line 5 or line 7, string interpolation is faster. Also, when commenting out line 8 (map[s] = s
), the version with the string interpolation is faster than the one with String(format:)
.
This took me quite a lot of time to figure out, since I would expect both methods to produce the same kind of string, but string interpolation to be always faster. Does anybody know why?
It's not the string interpolation vs the format string per se that takes time, and it has basically nothing to do with the dictionary insertion.
The significant thing is the amount of context switching between String and NSString that the rest of the code requires.
To see that, comment out the two lines that contain (s as NSString)
. Now you'll find that the format string version takes considerably longer than the string interpolation. That's because the format string introduces a context switch.
With your original code, sticking a String operation in the middle of two NSString operations means there are three pairs of context switches. That's the source of the slowness. In other words, if you're going to switch to NSString at all, do all NSString stuff until you're done, so there is just one context switch in one direction and one context switch back in the other direction.