Hex Values in Swift (With a Diversion Into Strings)

It's not uncommon to need to work with hex values. Swift is nice enough to understand hex numbers (prepended with "0x") which will then be internally treated as regular Ints.

However, because the hex value is now a regular Int, it can be inconvenient querying the hex value of that Int.

Swift has an initializer for basic data types that can take another type and a radix value to comprehend a number with an arbitrary base. For example, to create a String from an Int, but using base 16 you could initialize the String as follows:

String(0xFF0000, radix: 16)

which is equivalent to:

String(16711680, radix: 16)

If this seems unintuitive, it might be worth extending Int to give a simple function available to all Ints to generate hex Strings. An example of how we might do this is as follows:

Now, any time we have an Int and we'd like to see it as hex, we just call .asHex() on the number. By default, this function prepends "0x" to indicate it is a hex value, but that can be overridden by changing the withLeadingIndicator: parameter to false.

How about if we have a hex value expressed as a String and we want to represent get that as an Int. You might think it would be just as easy as the previous extension, but we run into two problems opportunities:
  1. Swift Strings are Unicode-based, which means individual characters are not all the same size and so asking for a substring of length 'n' is potentially ambiguous (the Apple Swift book has a good discussion of why this is so in the section Strings and Characters); and

  2. Swift is evolving quickly, and the syntax for String methods changes often.

Let's start with the extension on String:

This extension will take a hex String in the format "ABCDEF" or "0xABCDEF" or "#ABCDEF" and turn it into an Int.

As you can see, it is longer than the Int extension, even after taking account of the control flow. The reason for this is we need to specify an Index on the String. The Index is a value that looks a bit like an Integer, and serves the same function for advancing through a String as an integer might in other languages.

We can specify an Index from the beginning or the end of the String. Here we are working with the beginning of the string. The equivalent to .startIndex for the end of the String is .endIndex but it is important to remember that the endIndex value is the index after the last character in the String.

Example: for the String "Hi" the startIndex is 0 (like an array) but the endIndex is 2. If we wanted to get the Index for the last character in a String str we would specify str.index(self.endIndex, offsetBy: -1).

In the extension above, we take a substring from a specified point and go to the end of the String. if we wanted to start at the beginning and go to a specified point in str we would use str.substring(to: index) and here we need to be aware that to extends to just before the specified character (i.e., up to but not including).