Swift Tip: String to Data and Back
When converting a string into data, the return type is optional. For example:
let cafe: Data? = "Café".data(using: .utf8) // non-nil
Is it safe to force-unwrap this value? Can it ever return nil
? It depends. When you use a Unicode encoding (such as .utf8
or .utf16
), you can safely force-unwrap. Strings in Swift use Unicode internally, so encoding a string using a Unicode encoding will always succeed.
When you use other encodings, it is not safe to force-unwrap (unless you explicitly know that a string is guaranteed to be representable). It is easy to see this with an example:
let upsideDown = "🙃".data(using: .ascii)
ASCII can't represent emoji, and the conversion will fail. This isn't limited to emoji, Unicode can represent vastly more characters than ASCII.
How about the other way around? When we want to convert data into a string, can we be sure it's safe to force-unwrap? In this case, the answer is an unqualified no. Converting data into a string can always fail.
For example, here are the bytes for the cafe
variable above:
var bytes: Data = cafe! // [67, 97, 102, 195, 169]
When you read some bytes, you never know if it's valid Unicode. The last two bytes are the mark on top of the "é" and the "e". We can try to remove the "e" from the array, so that the mark has no character left to modify:
bytes.removeLast()
String(data: bytes, encoding: .utf8) // nil
As we can see, decoding fails. Unless you know exactly where the data comes from, you shouldn't rely on decoding to succeed, and you shouldn't force-unwrap the string. Sometimes, however, you might want to display what is in the string, even if there are decoding errors. There is a special initializer for this, which will try to repair the data, and inserts the "�" character (a replacement character) if it can't decode the data.
String(decoding: bytes, as: UTF8.self) // "Caf�"
TLDR
-
It's safe to force-unwrap the result of string-to-data transformation only when you use a Unicode encoding.
-
It's never safe to force-unwrap a data-to-string transformation.
To learn more about Swift's strings in depth, check out our book, Advanced Swift.