How to solve problems with bitwise operators in Swift
Learn to use the power of bitwise operations and option sets in iOS.
14 Dec 2020 · 6 min read

Recently, I had to solve the following task at work.
The server sends an integer value between 0 and 127 that represents the state of a weekdays selection. When the server sends a 0, no checkbox should be selected. For a 127, all check boxes should be selected. The numbers in between represent all the other states. The task was to evaluate this value to be able to preselect the appropriate checkboxes.

The logic behind the integer value is simple when we imagine that each weekday is represented by it's bit value:
mon tue wed thu fri sat sun0000000 - equals 0 - no weekday is selected0000011 - equals 3 - sat sun are selected1010101 - equals 85 - mon wed fri sun are selected1111100 - equals 124 - mon tue wed thu fri are selected1111111 - equals 127 - all days are selected
With this pattern, we are able to represent every state of the seven check boxes with numbers ranging from 0 to 127.

So, how do we convert the number send by the server into the correct checkboxes state?
The trivial solution
The first approach that might come to our mind could look like this:
switch weekdaysSelectionValue {case 0:monCheckbox.isChecked = falsetueCheckbox.isChecked = falsewedCheckbox.isChecked = falsethuCheckbox.isChecked = falsefriCheckbox.isChecked = falsesatCheckbox.isChecked = falsesunCheckbox.isChecked = falsecase 1:monCheckbox.isChecked = falsetueCheckbox.isChecked = falsewedCheckbox.isChecked = falsethuCheckbox.isChecked = falsefriCheckbox.isChecked = falsesatCheckbox.isChecked = falsesunCheckbox.isChecked = true...case 127:monCheckbox.isChecked = truetueCheckbox.isChecked = truewedCheckbox.isChecked = truethuCheckbox.isChecked = truefriCheckbox.isChecked = truesatCheckbox.isChecked = truesunCheckbox.isChecked = true}
Having 127 switch cases is a lot of fun, but let's look into a more generic approach to solve this with bitwise operators.
monCheckbox.isChecked = // get the bit on the 6th position & check if it is 0 or 1tueCheckbox.isChecked = // get the bit on the 5th position & check if it is 0 or 1wedCheckbox.isChecked = // get the bit on the 4th position & check if it is 0 or 1thuCheckbox.isChecked = // get the bit on the 3th position & check if it is 0 or 1friCheckbox.isChecked = // get the bit on the 2th position & check if it is 0 or 1satCheckbox.isChecked = // get the bit on the 1th position & check if it is 0 or 1sunCheckbox.isChecked = // get the bit on the 0th position & check if it is 0 or 1
To implement the solution above, let's look into how to work with bits in Swift.
Basics about bits in Swift
A bit is the smallest piece of information that can be 1 or 0. Eight bits together are called a byte. The unsigned UInt8 type in Swift is represented by 8 bits, that means we can represent 2⁸ = 256 different numbers with UInt8 which is enough for us since we only need 127 numbers.
UInt80 = 00000000 = 0 * 2^01 = 00000001 = 1 * 2^02 = 00000010 = 0 * 2^0 + 1 * 2^13 = 00000011 = 1 * 2^0 + 1 * 2^1...6 = 00000110 = 1 * 2^0 + 1 * 2^1 + 1 * 2^2...255 = 11111111 = 1 * 2^0 + 1 * 2^1 + 1 * 2^2 + 1 * 2^3 + 1 * 2^4 + 1 * 2^5 + 1 * 2^6
A signed Int8 type also represents 256 different numbers, but ranging from -128 to 127, since the most left bit is used to signify whether the integer is positive or negative. So theoretically, we could also use an Int8 for our task.
In Swift, when defining a number, we can choose to write down it's bit representation:
let value1: UInt8 = 3let value2: UInt8 = 0b00000011
In the example above, value1 and value2 are the same values, they are just written down differently. We could use basic operators on them like we are used to:
let value3 = 3 + 0b00000011 // 6let value4 = 3 - 0b00000011 // 0
Bitwise shifting and bitwise operators in Swift
Additionally to basic operators, Swift offers advanced operators for bit manipulations.
0b00000011 | 0b00000101 // The bitwise OR operator produces 0b000001110b00000011 & 0b00000101 // The bitwise AND operator produces 0b000000010b00000010 << 1 // The bitwise LEFT SHIFT operator << produces 0b00001000b00000010 >> 1 // The bitwise RIGHT SHIFT operator >> produces 0b0000001
- the OR operator | produces a 0 only if both bits are a 0. Otherwise it produces a 1.
- the AND operator & produces a 1 only if both bits are a 1. Otherwise it produces a 0.
- the LEFT SHIFT operator << shifts every bit to the left by a certain number of places. Any bits that are moved beyond the bounds are discarded.
- the RIGHT SHIFT operator >> does the same as the LEFT SHIFT operator in the other direction.
We can solve our task with the operators above. If you are interested in more of those operators, you can check out the official documentation.
The solution with bitwise operators
With the help of those operators, we now can do the following.
monCheckbox.isChecked = ((serverValue & 0b01000000) >> 6) == 1tueCheckbox.isChecked = ((serverValue & 0b00100000) >> 5) == 1wedCheckbox.isChecked = ((serverValue & 0b00010000) >> 4) == 1thuCheckbox.isChecked = ((serverValue & 0b00001000) >> 3) == 1friCheckbox.isChecked = ((serverValue & 0b00000100) >> 2) == 1satCheckbox.isChecked = ((serverValue & 0b00000010) >> 1) == 1sunCheckbox.isChecked = ((serverValue & 0b00000001) >> 0) == 1
What exactly is happening here? Let's pick one value to illustrate this.
1. Imagine, we get a 85 from the server. That is a 0b01010101 as bit representation.
2. Now, we want to know if the Friday's checkbox is checked. For that, we nullify all bits instead of the one on position 2 by using the AND operator.
0b01010101 & 0b00000100 // produces 0b000000100
3. Next, we want to know if the value on the second position is a 1 or a 0. For that, we shift 2 positions to the right, so the value is now at position 0.
0b000000100 >> 2 // produces 0b000000001
4. Finally, we can check if our produced value is a 0 or a 1 with the basic == operator.
0b000000001 == 1 // is true
Actually, we can even solve this without shifting. Instead of shifting to the right and checking if the value is 1, we can simply check if our value is not 0:
friCheckbox.isChecked = serverValue & 0b00000100 != 0
The solution with OptionSet
Now that we understand how to solve the task with bitwise operators, there is even a simpler solution. The Swift standard library offers the OptionSet that represents bit set types, where every bit represents a member of the set.
struct WeekdayOptions: OptionSet {let rawValue: Intstatic let sun = WeekdayOptions(rawValue: 1 << 0)static let sat = WeekdayOptions(rawValue: 1 << 1)static let fri = WeekdayOptions(rawValue: 1 << 2)static let thu = WeekdayOptions(rawValue: 1 << 3)static let wed = WeekdayOptions(rawValue: 1 << 4)static let tue = WeekdayOptions(rawValue: 1 << 5)static let mon = WeekdayOptions(rawValue: 1 << 6)}
After defining our weekday options as an OptionSet, we get all the logic behind it for free. To check if Monday is selected, we now can simply use the OptionSet's contains method.
let weekdayOptions = WeekdayOptions(rawValue: serverValue)monCheckbox.isSelected = weekdayOptions.contains(.mon)
Even though an OptionSet makes it easy, knowing the bit operators and how it works behind the scenes makes its usage more clear.
Of course, an OptionSet offers a lot more useful methods. You can check them out in the official documentation.
Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips