What is the difference between Data and [UInt8]?

When designing APIs that deal with byte-level data, is there a good reason to use Data as a buffer instead of [UInt8]?

From what I understand, Arrays of trivial types like UInt8 are always stored contiguously in memory. But I also know even SwiftNIO uses its own ByteBuffer type instead of [UInt8]. What do these buffer types do differently, and am I giving up on valuable performance or safety by simply using [UInt8]?

Answered by DTS Engineer in 707507022

When designing APIs that deal with byte-level data, is there a good reason to use Data as a buffer instead of [UInt8]?

There is no simple answer to this. Data has a lot of history, and that’s both good and bad. On the plus side, it’s well integrated, both into Swift itself and, especially, into Apple platforms. On the minus side, that history results in various oddities.

A lot of folks avoid Data because they want to avoid Foundation. IMO that’s not a good reason. On Apple platforms Foundation is omnipresent. Foundation is also available for non-Apple platforms and, while it’s does have its issues there, basic stuff like Data works just fine.

SwiftNIO’s ByteBuffer is reminiscent of Data but it hits a different design point, one that was specifically crafted to meet SwiftNIO’s requirements. If you want to learn more about that, I second Matt’s recommendation to ask about it on Swift Forums.

Personally, I use both Data and [UInt8] depending on the situation:

  • I generally lean towards Data because its features make my life easier. Examples of this include reading from and writing to disk, text encodings, and integration with higher-level frameworks.

  • In some situations [UInt8] is actually easier than Data. For example, if you’re calling a C API that works with pointers to UInt8, having a [UInt8] on the Swift side means that you can take advantage of Swift’s array-to-pointer integration. For more on that, see The Peril of the Ampersand.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

UInt8 is an unsigned integer which can store only positive values.

When designing APIs that deal with byte-level data, is there a good reason to use Data as a buffer instead of [UInt8]?

On Apple platforms, Data has a variety of APIs built into Foundation for writing bytes to disk, encoding, or decoding bytes. If you need to do any of these operations with an array of UInt8 then chances are that you would need to transfer these bytes into a Data container anyways before doing so. Sp that is one good reason to use Data on Apple platforms.

If you are strictly working with the bytes and never going back up to Data to write or decode then an array of bytes may be all you need.

Regarding:

But I also know even SwiftNIO uses its own ByteBuffer type instead of [UInt8]. What do these buffer types do differently

For further questions about SwiftNIO, I would ask on the Swift Forums, but I can tell you that one reason that ByteBuffer is used is because it is portable across Apple and non-Apple platforms. ByteBuffer also accepts [UInt8] as an acceptable type to write to the buffer.

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com
Accepted Answer

When designing APIs that deal with byte-level data, is there a good reason to use Data as a buffer instead of [UInt8]?

There is no simple answer to this. Data has a lot of history, and that’s both good and bad. On the plus side, it’s well integrated, both into Swift itself and, especially, into Apple platforms. On the minus side, that history results in various oddities.

A lot of folks avoid Data because they want to avoid Foundation. IMO that’s not a good reason. On Apple platforms Foundation is omnipresent. Foundation is also available for non-Apple platforms and, while it’s does have its issues there, basic stuff like Data works just fine.

SwiftNIO’s ByteBuffer is reminiscent of Data but it hits a different design point, one that was specifically crafted to meet SwiftNIO’s requirements. If you want to learn more about that, I second Matt’s recommendation to ask about it on Swift Forums.

Personally, I use both Data and [UInt8] depending on the situation:

  • I generally lean towards Data because its features make my life easier. Examples of this include reading from and writing to disk, text encodings, and integration with higher-level frameworks.

  • In some situations [UInt8] is actually easier than Data. For example, if you’re calling a C API that works with pointers to UInt8, having a [UInt8] on the Swift side means that you can take advantage of Swift’s array-to-pointer integration. For more on that, see The Peril of the Ampersand.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

What is the difference between Data and [UInt8]?
 
 
Q