为什么 UIControlState 是 Struct 而不是 Enum?
UIControlState 从根本上说不是枚举。枚举是“OR”类型。
enum Foo {
case a, b, c
}
var f = Foo.a
f = .b
f = .c
所以,在上面的例子中,f 可以持有.a 或 .b 或 .c。
但UIControlState 的情况并非如此;这是一个选项集。一个选项集可以包含一组一个或多个案例。因此它是一个“AND”类型,我们通常使用符合OptionSet 协议的struct 来实现它们。
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
因此,您可以在上面的示例中看到,b 可以包含.a、.b 和.c 的任意集合。
UIControlState 也是如此;例如,我们可以谈论被聚焦和突出显示的控制状态:
let controlState: UIControlState = [.highlighted, .focused]
如果是enum,我们只能谈论控件是否处于一个特定状态,例如仅突出显示或仅聚焦。但这不是一个正确的模型,因为控件可以同时处于多个不同的状态。
另外值得注意的是,对于UIControlState,.normal 的情况相当于一个空的选项集[];它的意思是“未突出显示或聚焦或选择或禁用或......”。
其次,当我查看 UIStateControl 的文档时,我
请参阅“常量”的定义,例如:
static var normal: UIControlState
这不太准确。自动生成的 Swift 标头中的 UIControlState 声明如下所示:
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
}
您会在末尾看到{ get }。这意味着它们只是 只读 属性。它们的实际实现方式(如let 常量、var 只读计算属性等)是纯粹的实现细节。
在这种情况下,UIControlState 在 UIKit 中使用 NS_OPTIONS 宏定义,Swift imports in as an OptionSet 符合结构,每个选项值都是静态只读属性。
UIControlState 的静态属性如何定义为“UIControlState”类型?这不是递归的吗?
不,它根本不是递归的。请记住,它们是static 属性,因此只不过是命名空间为UIControlState 的全局变量(它们甚至不需要存储;它们可以被计算,不过,这又是一个实现细节)。
如果它们是 instance 存储属性,那么它确实是递归的。但他们不是。