Taming Foundation Constants into Swift Enums

For most of Cocoa, Apple has done a nice job of wrapping the APIs in native Swift entities. In particular, sets of constants that exist in NS_ENUM enumerations are imported as Swift enums with associated raw values. The situation is a little different when it comes to Foundation. In Foundation, many of the constants are not gathered into C enums and so they are not imported into Swift as nicely.

In this post I will look at what code is necessary to wrap up Foundation constants as a Swift enum and then I will introduce a simple tool to automate the code generation.

A Naïve First Attempt

I first became aware of this issue when I was writing some code to try to make the Keychain a little more palatable to use in Swift. I’ll use as an example throughout this post the manifest constants for the kSecAttrAccessible attribute in a keychain item. These are defined in SecItem.h as:

extern CFTypeRef kSecAttrAccessibleWhenUnlocked
extern CFTypeRef kSecAttrAccessibleAfterFirstUnlock
extern CFTypeRef kSecAttrAccessibleAlways
extern CFTypeRef kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
extern CFTypeRef kSecAttrAccessibleWhenUnlockedThisDeviceOnly
extern CFTypeRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
extern CFTypeRef kSecAttrAccessibleAlwaysThisDeviceOnly


Although it is not apparent from these declarations, the underlying type of these constants is CFStringRef.

A first attempt to wrap these values in a Swift enum might look something like this.

enum Accessible : String {
    case WhenUnlocked =
            kSecAttrAccessibleWhenUnlocked,
        AfterFirstUnlock =
            kSecAttrAccessibleAfterFirstUnlock,
        Always =
            kSecAttrAccessibleAlways,
        WhenPosscodeSetThisDeviceOnly =
            kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
        WhenInlockedThisDeviceOnly =
            kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
        AfterFirstUnlockThisDeviceOnly =
            kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
        AlwaysThisDeviceOnly =
            kSecAttrAccessibleAlwaysThisDeviceOnly
}


Unfortunately this does not work, because the raw values of enum cases must be literals. I could have determined the values of the constants and explicitly equated these with the case values, but that would break in the (albeit unlikely) even of the value of a constant changing in some future version of the OS.

Conforming to RawRepresentable

A better solution is to have the enum conform to RawRepresentable. For Swift 1.1, the RawRepresentable protocol is defined as:

protocol RawRepresentable {
    typealias RawValue
    init?(rawValue: RawValue)
    var rawValue: RawValue { get }
}

An initializer must be provided to create a enum from a rawValue and a computed property to perform the opposite conversion. In our example enum this would look something like this.

public enum Accessible : RawRepresentable {
	case WhenUnlocked, AfterFirstUnlock, Always,
		WhenPasscodeSetThisDeviceOnly, WhenUnlockedThisDeviceOnly,
		AfterFirstUnlockThisDeviceOnly, AlwaysThisDeviceOnly

	public init?(rawValue: String) {
		if rawValue == String(kSecAttrAccessibleWhenUnlocked) {
			self = WhenUnlocked
		}
		else if rawValue == String(kSecAttrAccessibleAfterFirstUnlock) {
			self = AfterFirstUnlock
		}
		else if rawValue == String(kSecAttrAccessibleAlways) {
			self = Always
		}
		else if rawValue == String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly) {
			self = WhenPasscodeSetThisDeviceOnly
		}
		else if rawValue == String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly) {
			self = WhenUnlockedThisDeviceOnly
		}
		else if rawValue == String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly) {
			self = AfterFirstUnlockThisDeviceOnly
		}
		else if rawValue == String(kSecAttrAccessibleAlwaysThisDeviceOnly) {
			self = AlwaysThisDeviceOnly
		}
		else {
			return nil
		}
	}

	public var rawValue: String {
		switch self {
			case WhenUnlocked:
				return String(kSecAttrAccessibleWhenUnlocked)
			case AfterFirstUnlock:
				return String(kSecAttrAccessibleAfterFirstUnlock)
			case Always:
				return String(kSecAttrAccessibleAlways)
			case WhenPasscodeSetThisDeviceOnly:
				return String(kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)
			case WhenUnlockedThisDeviceOnly:
				return String(kSecAttrAccessibleWhenUnlockedThisDeviceOnly)
			case AfterFirstUnlockThisDeviceOnly:
				return String(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly)
			case AlwaysThisDeviceOnly:
				return String(kSecAttrAccessibleAlwaysThisDeviceOnly)
		}
	}
}

Other Nice Extensions

It can often be useful to be able to print the symbol for an enum (not its raw value) both during debugging and when presenting error information to the user. This can be achieved by extending the enum to conform to Printable.

extension Accessible : Printable {
    public var description : String {
        switch self {
        case WhenUnlocked: return "WhenUnlocked"
        case AfterFirstUnlock: return "AfterFirstUnlock"
        case Always: return "Always"
        case WhenPasscodeSetThisDeviceOnly: return "WhenPasscodeSetThisDeviceOnly"
        case WhenUnlockedThisDeviceOnly: return "WhenUnlockedThisDeviceOnly"
        case AfterFirstUnlockThisDeviceOnly: return "AfterFirstUnlockThisDeviceOnly"
        case AlwaysThisDeviceOnly: return "AlwaysThisDeviceOnly"
        }
    }
}

Finally it would also be nice to be able to enumerate all the values of the enum. This can be done the extending the enum with an allValues array.

extension Accessible {
    public static let allValues: [Accessible] = [WhenUnlocked, AfterFirstUnlock, Always, WhenPasscodeSetThisDeviceOnly, WhenUnlockedThisDeviceOnly, AfterFirstUnlockThisDeviceOnly, AlwaysThisDeviceOnly]
}

Automating the Procedure: enumtool

At this point we have a really nice Swift enum that wraps the Foundation constants, but what a lot of boilerplate code! Let’s face there is nothing more soul-destroying then spending hours cranking out boilerplate.

To automate this process, I created a little command line tool, written in swift and I have made it available on GitHub.

If the constants in the above example had been extracted, one per line, into a file called SecAttrAccessible.txt running enumtool as follows would create all the code in this article.

enumtool -i SecAttrAccessible.txt -n Accessible -r String -o Accessible.swift

More information about enumtool can be found at the enumtool GitHub repository. I hope it may be of some use to you.


About idz

A professional software engineer dabbling in iOS app development.
This entry was posted in Swift. Bookmark the permalink.

One Response to Taming Foundation Constants into Swift Enums

  1. Pingback: EVERYTHING YOU WANT – Swift resources | swiftioscodetutorial

Leave a Reply