String, Array, and Dictionary are all structs (that get stored on the stack), but their dynamically sized "content" is stored in a buffer allocated on the stack. This buffer is part of an object, which is referenced by the struct.
Take Array for example, whose source code is available on GitHub (as with the rest of the Swift programming language).
You can see that the Array struct contains a single member: internal var _buffer: _Buffer. For Array, this _Buffer type is a typealias for either _ArrayBuffer<Element> (if the Objective C runtime is being used, for faster bridging to/from NSArray), or _ContiguousArrayBuffer<Element>.
Having the _Buffer object wrapped up in a struct (Array) like this is what allows for Array to have copy-on-write behavior. Copies of the Array can be made very cheaply by simply copying the _buffer reference from the source array to the destination array. When a mutable operation is done, Array checks to see if its _buffer is uniquely referenced (that is, no other Array shares the same _buffer`).
- If it is uniquely referenced, then the mutable operation can be done directly on the
_buffer, without the possibility of unintentionally modifying another Array (since there is no other Array sharing this _buffer.)
- If it is not uniquely referenced, then a copy is made, and the mutable operation is performed on the copy.
#mind-blown