I agree with @eskimo that this is confusing given the current state of the documentation, but that it's not a bug. When you give
Data a no-copy buffer, it needs to own that buffer in order to correctly handle deallocation. From
NSData.init(bytesNoCopy:length:freeWhenDone:) on the
true , the returned object takes ownership of the
bytes pointer and frees it on deallocation.
The same is implicitly true for the other
deallocator cases, though it could be spelled out more clearly.
There are also cases in which
Data must copy, despite being initialized with
If the result is mutated and is not a unique reference, then the
Data will still follow copy-on-write semantics. In this case, the copy will use its own deallocator. Therefore, it is usually best to only use this initializer when you either enforce immutability with
let or ensure that no other references to the underlying data are formed.
bytesNoCopy initializers take ownership* of the buffer, you can't rely on being able to access the buffer through any reference except the
Data reference itself, and given that
Data now owns the buffer and may need to make copies of the data in the future, it is valid for it to copy the data into a more efficient representation immediately as long as it cleans up the underlying buffer (which @eskimo shows) as an optimization.
Now, if you need a guarantee that the buffer itself will remain in use even if you have multiple references to the data objects,
NSData would be preferred over
Data because of its object semantics.
*there is one case I can think of where this is more unexpected than others: when you pass in a deallocator of
Data can't necessarily take ownership of the buffer. In those cases, it should likely make stronger guarantees about not copying up-front (though again,
Data must be able to copy in order to maintain value semantics).