Quickest way to concatenate strings in Swift 2
I ran the following code in the simulator and on an iPhone6S Plus. The results in both cases showed the string1 + " " + string2
addition faster for the strings I used. I didn't try with different types of strings, optimizations, etc. but you can run the code and check for your particular strings etc. Try running this code online in the IBM Swift Sandbox.
The timer struct is from here: Measure elapsed time in Swift
To run the code create a single view application in Xcode and add the following code to the ViewController:
import UIKit
import CoreFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a = "abscdefghi jkl¢€@sads dljlæejktæljæ leijroptjiæa Dog! iojeg r æioej rgæoija"
let b = a
timeStringAdding(a, string2: b, times: 1_000_000, repetitions: 5)
}
struct RunTimer: CustomStringConvertible {
var begin: CFAbsoluteTime
var end:CFAbsoluteTime
init() {
begin = CFAbsoluteTimeGetCurrent()
end = 0
}
mutating func start() {
begin = CFAbsoluteTimeGetCurrent()
end = 0
}
@discardableResult
mutating func stop() -> Double {
if (end == 0) { end = CFAbsoluteTimeGetCurrent() }
return Double(end - begin)
}
var duration: CFAbsoluteTime {
get {
if (end == 0) { return CFAbsoluteTimeGetCurrent() - begin }
else { return end - begin }
}
}
var description: String {
let time = duration
if (time > 100) {return " \(time/60) min"}
else if (time < 1e-6) {return " \(time*1e9) ns"}
else if (time < 1e-3) {return " \(time*1e6) µs"}
else if (time < 1) {return " \(time*1000) ms"}
else {return " \(time) s"}
}
}
func timeStringAdding(string1:String, string2:String, times:Int, repetitions:Int) {
var newString = ""
var i = 0
var j = 0
var timer = RunTimer()
while j < repetitions {
i = 0
timer.start()
while i < times {
newString = string1 + " " + string2
i += 1
}
print("+ add \(timer)")
i = 0
timer.start()
while i < times {
newString = "\(string1) \(string2)"
i += 1
}
print("\\( add \(timer)")
j += 1
}
}
}
On an iPhone 6S Plus, it gave:
+ add 727.977991104126 ms
\( add 1.1197350025177 s
+ add 693.499982357025 ms
\( add 1.11982899904251 s
+ add 690.113961696625 ms
\( add 1.12086200714111 s
+ add 707.363963127136 ms
\( add 1.13451600074768 s
+ add 734.095990657806 ms
\( add 1.19673496484756 s
And on the simulator (iMac Retina):
+ add 406.143009662628 ms
\( add 594.823002815247 ms
+ add 366.503953933716 ms
\( add 595.698952674866 ms
+ add 370.530009269714 ms
\( add 596.457958221436 ms
+ add 369.667053222656 ms
\( add 594.724953174591 ms
+ add 369.095981121063 ms
\( add 595.37798166275 ms
Most of the time is allocation and freeing memory for the string structs and for those really curious run the code in the Instruments panel
with Time Profiler
usage and see how the time is allocated for alloc and free etc, in relation to the machine code which is shown there also.
This question piqued my curiosity, so I put this into a new project. These are quick and dirty benchmarks and should be taken with the usual grains of salt, but the results were intriguing.
var string1 = "This"
var string2 = "that"
var newString: String
let startTime = NSDate()
for _ in 1...100000000 {
newString = string1 + " " + string2
}
print("Diff: \(startTime.timeIntervalSinceNow * -1)")
In 6 runs on the simulator running on my MacBook Pro (mid-2014 i7, 2.5GHz), the output to the debug console averaged 1.36 seconds. Deployed as debug code to my iPhone 6S, the average of all the outputs in 6 runs was 1.33 seconds.
Using the same code but changing the line where the strings are concatenated to this...
newString = "\(string1) \(string2)"
...gave me rather different results. In 6 runs on the simulator, the average time reported on the debug console was 50.86 seconds. In 6 runs on the iPhone 6S, the average run time was 88.82 seconds. That's almost 2 orders of magnitude's difference.
These results suggest that if you have to concatenate a large number of strings, you should use the +
operator rather than string interpolation.