Why is UIControlState a Struct and not an Enum?
UIControlState is fundamentally not an enumeration. An enumeration is an "OR" type.
enum Foo {
case a, b, c
}
var f = Foo.a
f = .b
f = .c
So, in the above example, f can hold .a or .b or .c.
But that's not the case with UIControlState; it's an option set. An option set can hold a set of one or more cases. It is therefore an "AND" type, and we usually implement them with a struct that conforms to the OptionSet protocol.
struct Bar : OptionSet {
let rawValue: Int
// Note that the raw values are unique powers of two.
// Each bit represents a flag determining if a given case is present.
static let a = Bar(rawValue: 1) // 001
static let b = Bar(rawValue: 2) // 010
static let c = Bar(rawValue: 4) // 100
}
var b = Bar.a // .a but not .b or .c
b = [.a, .b] // .a and .b, but not .c
b = [.c, .a, .b] // .a and .b and .c
So, you can see in the above example, b can hold any set of .a, .b and .c.
And that's the same with UIControlState; we can for example talk about a control state of being focused and highlighted:
let controlState: UIControlState = [.highlighted, .focused]
If it were an enum, we could only talk about whether a control was in one specific state, such as only highlighted or only focussed. But that's not a correct model, because controls can be in multiple different states at once.
Also it's worth noting that with UIControlState, the .normal case is equivalent to an empty set of options []; it means "not highlighted or focussed or selected or disabled or ...".
Secondly, when I look at the documentation for UIStateControl, all I
see are definitions of "constants," e.g.:
static var normal: UIControlState
That's not quite accurate. The UIControlState declaration in the auto-generated Swift header looks like this:
public struct UIControlState : OptionSet {
public init(rawValue: UInt)
public static var normal: UIControlState { get }
public static var highlighted: UIControlState { get } // used when UIControl isHighlighted is set
public static var disabled: UIControlState { get }
public static var selected: UIControlState { get } // flag usable by app (see below)
@available(iOS 9.0, *)
public static var focused: UIControlState { get } // Applicable only when the screen supports focus
public static var application: UIControlState { get } // additional flags available for application use
public static var reserved: UIControlState { get } // flags reserved for internal framework use
}
You'll note the { get } at the end. This means that they are just read only properties. How they are actually implemented (as let constants, var read-only computed properties etc.) is a pure implementation detail.
In this case, UIControlState is defined in UIKit with the NS_OPTIONS macro, which Swift imports in as an OptionSet conforming structure with each option value being a static read-only property.
How is UIControlState's static property defined as type "UIControlState?" Isn't that recursive?
No, it's not recursive at all. Remember, they're static properties, and as such are nothing more than global variables namespaced to UIControlState (and they don't even need to have storage; they could be computed, although, again that's an implementation detail).
If they were instance stored properties, then it would indeed be recursive. But they aren't.