I come from a C# background where System.String
is immutable and string concatenation is relatively expensive (as it requires reallocating the string) we know to use the StringBuilder
type instead as it preallocates a larger buffer where single characters (Char
, a 16-bit value-type) and short strings can be concatenated cheaply without extra allocation.
I'm porting some C# code to Swift which reads from a bit-array ([Bool]
) at sub-octet indexes with character lengths less than 8 bits (it's a very space-conscious file format).
My C# code does something like this:
StringBuilder sb = new StringBuilder( expectedCharacterCount );
int idxInBits = 0;
Boolean[] bits = ...;
for(int i = 0; i < someLength; i++) {
Char c = ReadNextCharacter( ref idxInBits, 6 ); // each character is 6 bits in this example
sb.Append( c );
}
In Swift, I assume NSMutableString
is the equivalent of .NET's StringBuilder
, and I found this QA about appending individual characters ( How to append a character to string in Swift? ) so in Swift I have this:
var buffer: NSMutableString
for i in 0..<charCount {
let charValue: Character = readNextCharacter( ... )
buffer.AppendWithFormat("%c", charValue)
}
return String(buffer)
But I don't know why it goes through a format-string first, that seems inefficient (reparsing the format-string on every iteration) and as my code is running on iOS devices I want to be very conservative with my program's CPU and memory usage.
As I was writing this, I learned my code should really be using UnicodeScalar
instead of Character
, problem is NSMutableString
does not let you append a UnicodeScalar
value, you have to use Swift's own mutable String
type, so now my code looks like:
var buffer: String
for i in 0..<charCount {
let x: UnicodeScalar = readNextCharacter( ... )
buffer.append(x)
}
return buffer
I thought that String
was immutable, but I noticed its append
method returns Void
.
I still feel uncomfortable doing this because I don't know how Swift's String
type is implemented internally, and I don't see how I can preallocate a large buffer to avoid reallocations (assuming Swift's String
uses a growing algorithm).