Working with bytes in Swift 4

Sometimes there is a need to implement an algorithm for encryption/decryption on strings, files or other data in your Swift project. Conversion for this type of algorithms from other languages (such as Java) to Swift, unfortunately is not straight forward.

Unicode Scalars

Behind the scenes, Swift’s native String type is built from Unicode scalar values. A Unicode scalar is a unique 21-bit number for a character or modifier, such as U+0061 for LATIN SMALL LETTER A ("a") , or U+1F425 for FRONT-FACING BABY CHICK ("🐥")

In Swift a Character can be constructed from a UnicodeScalar value. And we can build a UnicodeScalar from an Int. This allows many conversions.

With utf8 and utf16, both properties on a String, we can access all Int values of the characters of a String. With these properties, we can apply number-based conversions to characters.

Note:

Image for post
Comparison table for primitive data types

Converting String to byte array and short array

let string: String = "abcd"let byteArray: [UInt8] = string.utf8.map{UInt8($0)}let shortArray: [UInt16] = string.utf16.map{UInt16($0)}// There is also another way with more encodingsif let data: Data = string.data(using: .windowsCP1252, allowLossyConversion: true) {// Now you can simply loop thru the bytes in datafor i in 0..<data.count {data[i] // UInt8 value}// Or if you still need it as UInt8 arraylet byteArrayFromData: [UInt8] = [UInt8](data)}
// Read more about data(using encoding: UInt, allowLossyConversion lossy: Bool) -> Data? from Apple doc:
https://developer.apple.com/documentation/foundation/nsstring/1413692-data

Converting byte array and short array to String

let byteArray: [UInt8] = [97, 98, 99, 100]let stringFromByteArray = String(data: Data(bytes: byteArray), encoding: .utf8)let shortArray: [UInt16] = [97, 98, 99, 100]let stringFromShortArray = shortArray.reduce("", {$0 + String(UnicodeScalar($1)!)})

Converting Character to byte and short

let character: Character = "a"let byte: UInt8 = String(character).utf8.map{UInt8($0)}[0]let short: UInt16 = String(character).utf16.map{UInt16($0)}[0]

Converting byte and short to Character

let byte: UInt8 = 100let characterFromByte: Character = Character(UnicodeScalar(byte))let short: UInt16 = 100// UnicodeScalar init with parameter value of UInt16 is optional
let characterFromShort: Character = Character(UnicodeScalar(short)!)

Here is a Character class extension for simplifying the byte and short conversion

Useful bit-wise operators

Image for post
Bitwise operators
Image for post
Bitwise assignment operators

To check all the available operators visit apple’s documentation from the links provided below.

Before you dive into converting an algorithm to Swift, there is one more important thing that you will need to know, Swift uses Unsigned Integers.

Unsigned and Signed Integers

Swift’s UInt8 — The UInt8 data type is an 8-bit unsigned integer. It has a minimum value of 0 and a maximum value of 255 (inclusive)

Java’s byte — The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive)

The difference between Java’s short and Swift’s UInt16 is similar to byte and UInt8 from above, so we can use the next definition for reference.

Image for post

Java was used as an example programming language to point out the difference. There are other languages that use signed integers for byte and short.

More information about unsigned and signed integers can be found here: https://www.tutorialspoint.com/unsigned-and-signed-binary-numbers

Written by

iOS Engineer | more info about me @ shukov.site

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store