How to Work With Bitmasks in Swift

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy

A surprising number of developers struggle with bitmasks and bitwise operations. If you've had problems working with bitmasks, then I have good news for you. Swift's standard library makes this easy. In this tutorial, I'd like to walk you through an example I worked on last week for an application I'm working on.

Scheduling a Reminder In the Namaste Application

OptionSet Protocol

The application I'm currently working on has the ability to schedule reminders. The feature is similar to that of the built-in Clock application. A reminder or alarm can be scheduled on a specific day, but it can also be repeated on other days. A bitmask was the logical solution to solve this problem. In other words, I want to store the schedule for a reminder in a single value.

Scheduling a Timer In the Clock Application

Let me show you how easy and elegant Swift makes the implementation. Open Xcode and create a new playground.

The protocol we are interested in is the OptionSet protocol. As the name of the protocol implies, an OptionSet instance represents a set of options. This is exactly what we need for a bitmask.

I've named the type we are creating Schedule. Notice that it's a structure that conforms to the OptionSet protocol.

struct Schedule: OptionSet {

}

The compiler immediately warns us that Schedule doesn't conform to the RawRepresentable protocol. What is that about? Press Command and click OptionSet to navigate to the declaration of the OptionSet protocol. The protocol declaration shows us that OptionSet inherits from the RawRepresentable protocol.

public protocol OptionSet : SetAlgebra, RawRepresentable {

    associatedtype Element = Self

    public init(rawValue: Self.RawValue)

}

This means the Schedule structure also needs to conform to the RawRepresentable protocol. This is easy enough, though. We declare a constant property, rawValue, of type Int.

struct Schedule: OptionSet {

    let rawValue: Int

}

As a result, we get an initializer for free, init(rawValue:).

Creating an Option Set

We've defined an option set, but how do we work with instances of the Schedule structure? The Swift standard library comes to the rescue. For each option, we declare a static member. Notice that we use bitwise operators to define the raw value for each static member. Each static member has a unique value. That is key.

struct Schedule: OptionSet {

    let rawValue: Int

    static let monday       = Schedule(rawValue: 1 << 0)
    static let tuesday      = Schedule(rawValue: 1 << 1)
    static let wednesday    = Schedule(rawValue: 1 << 2)
    static let thursday     = Schedule(rawValue: 1 << 3)
    static let friday       = Schedule(rawValue: 1 << 4)
    static let saturday     = Schedule(rawValue: 1 << 5)
    static let sunday       = Schedule(rawValue: 1 << 6)

}

Using this approach, the syntax may remind you of working with enumerations.

let schedule = Schedule.monday

Or

let schedule: Schedule = .monday

Working With Options Sets

Working with options sets is easy and intuitive. Take a look at the example below in which we assign the static member wednesday to a variable.

let schedule = Schedule.wednesday

Or

let schedule: Schedule = .wednesday

You can use an array to create an option set with one or more static members. It doesn't get easier than this. If you've worked with bitmasks in Objective-C, then I'm sure you agree Swift's implementation is easier to work with, less confusing, and more intuitive.

let weekend = [Schedule.saturday, Schedule.sunday]

Or

let weekend: Schedule = [.saturday, .sunday]

You can also use the initializer of the Schedule struct to create an option set. This is especially useful if you've stored the raw value in, for example, a database.

let schedule = Schedule(rawValue: 127)

The rawValue property provides access to the raw value of the option set.

schedule.rawValue

Manipulating Options Sets

Creating option sets is straightforward. But it doesn't stop here. The OptionSet protocol defines a collection of methods that make working with option sets easy and powerful. Take a look at the following example in which we combine two option sets.

let schedule1: Schedule = .monday
let schedule2: Schedule = .tuesday

let union = schedule1.union(schedule2)

You can also ask an option set whether it contains a particular element.

let weekend: Schedule = [.saturday, .sunday]

if weekend.contains(.friday) {
    print("The schedule contains Friday.")
} else {
    print("The schedule doesn't contain Friday.")
}

And you can use insert(_:) and remove(_:) to insert and remove members from an existing option set.

var schedule: Schedule = []

schedule.insert(.monday)
schedule.remove(.thursday)

Notice that an empty option set is represented by an empty array.

var schedule: Schedule = []

One More Trick

You can also define static members for convenience. The example we've created in this tutorial makes it easy to work with schedules. We can define a few additional static members to make this even easier, more convenient.

The weekend static member defines an option set that contains the values stored in .saturday and .sunday. The weekdays static member only contains the days of the week.

struct Schedule: OptionSet {

    let rawValue: Int

    static let monday       = Schedule(rawValue: 1 << 0)
    static let tuesday      = Schedule(rawValue: 1 << 1)
    static let wednesday    = Schedule(rawValue: 1 << 2)
    static let thursday     = Schedule(rawValue: 1 << 3)
    static let friday       = Schedule(rawValue: 1 << 4)
    static let saturday     = Schedule(rawValue: 1 << 5)
    static let sunday       = Schedule(rawValue: 1 << 6)

    static let weekend: Schedule    = [.saturday, .sunday]
    static let weekdays: Schedule   = [.monday, .tuesday, .wednesday, .thursday, .friday]

}

The OptionSet protocol is a wonderful member of Swift's standard library. Working with bitmasks doesn't have to be complex or cumbersome.

Later this week, I show you how to create a basic user interface that allows users to define a schedule using the Schedule struct.

Download Your Free Copy of
The Missing Manual
for Swift Development

The Guide I Wish I Had When I Started Out

Join 20,000+ Developers Learning About Swift Development

Download Your Free Copy