Swift Strings are value types that do not have reference counting. But the characters that contain the string are stored on the heap inside the storage container of the reference type and have a reference count.
This is why Swift Strings has a copy to optimize recording, for example, of other collections -
Using strings - as well as any other reference type - within Structs - is not a good idea for performance, because each assignment of Struct itself retains all other reference types and String.
When you have a value type that contains an N reference type, with each assignment / deletion you need to save / release N. And you will have the overhead of copying for the value types.
But if you define a reference type containing N reference types, then with each assignment / deletion you will have only 1 save / release operation.
For exp:
struct Label { var text: String var font: UIFont func draw() { } } let label1 = Label(text: "Hi", font: font) let label2 = label1 retain(label2.text._storage) retain(label2.font)
If Label was implemented as a class, it will be
class Label { var text: String var font: UIFont func draw() { } } let label1 = Label(text: "Hi", font: font) let label2 = label1 retain(label2)
On the other hand, this approach contradicts the Struct Philosophy security proposal. The same copies will be distributed among all copies.
Since save / free operations are on the heap and must be thread safe, there is significant cost to this operation.
So, if you really need great performance, including microoptimization, and you want to use value types wisely , you should consider this approach.
PS: this approach does not change with Swift 4, copying to write is another optimization. It creates a copy only if value types containing reference types with multiple references are mutated.