我对UIControlState的运行方式感到有些困惑。具体来说,如果我看下面的例子:
sender.setTitle("NewTitle", for: UIControlState.normal)
据我所知,这为Button(发件人)的正常状态设定了标题。我原以为.normal是UIControlState类型的Enum值,但是后来才知道它是一个带常量的结构。第一个问题:
其次,当我查看UIStateControl的文档时,我看到的只是"常量的定义,"例如:
static var normal: UIControlState
第二/第三个问题:
为什么"常数"用于" var"定义的UIStateControl而不是"让?"
如何将UIControlState的静态属性定义为" UIControlState?"这不是递归的吗?
答案 0 :(得分:5)
为什么UIControlState是结构而不是枚举?
UIControlState
从根本上不是枚举。枚举是“OR”类型。
enum Foo {
case a, b, c
}
var f = Foo.a
f = .b
f = .c
因此,在上面的示例中,f
可以保留.a
或 .b
或 .c
。< / p>
但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
的全局变量(它们甚至不需要存储;它们可以被计算,但是,这也是一个实施细节)。
如果它们是实例存储的属性,那么它确实是递归的。但他们不是。
答案 1 :(得分:1)
为什么UIControlState是结构而不是枚举?
由于UIControlEvents与使用 Objective-C 构建的UIKit框架相关,因此意味着它与Swift枚举无关。
如果目的是为了通过一个州,为什么这个被定义为 enum with .normal作为案例之一?
然而,UIControlEvents
struct符合OptionSet协议,它是Swift编程语言的一部分;符合OptionSet
的目的是代表bit mask types。如果您尝试创建符合OptionSet
的结构,您会注意到需要实现init(rawValue:)
初始值设定项和rawValue
属性,例如:
struct CustomOptions: OptionSet {
let rawValue: Int
static let easy = CustomOptions(rawValue: 0b00000001) // 1
static let medium = CustomOptions(rawValue: 0b00000010) // 2
static let hard = CustomOptions(rawValue: 0b00000011) // 3
static let unfair = CustomOptions(rawValue: 0b00000100) // 4
}
let myOption = CustomOptions.medium
print(myOption) // CustomOptions(rawValue: 2)
请注意,rawValues
通常是两个唯一的幂(1,2,4,8,16等),但我只是为它们分别为1,2,3和4简洁的目的。
因为选项具有原始值,所以您可以调用该选项,甚至无需提及结构的内容,请考虑以下内容:
func doSomething(param: CustomOptions) {
// ...
}
// you don't have to: doSomething(param: CustomOptions.medium)
// instead, you could call it like this:
doSomething(param: CustomOptions.medium)
因此:
sender.setTitle("title", for: .normal)
Enum VS Structure符合OptionSet
但是等等!为什么要使用符合OptionSet
协议而不是枚举的结构?
除了提到的与使用的编程语言之间的差异有关的内容之外,enum是一次表示单值的,但OptionSet结构可以是组合的表示单个值中的值,声音混乱?请考虑以下事项:
let combinedOption: CustomOptions = [.easy, .medium]
print(combinedOption) // CustomOptions(rawValue: 3)
初看起来,[.easy, .medium]
可能很棘手,看起来像一个阵列,但事实并非如此!实际上它是一个CustomOptions
实例,它是easy
和medium
选项的组合(求和)。
因此:
sender.setTitle("title", for: [.normal, .disabled])
为什么&#34;常数&#34;用于&#34; var&#34;定义的UIStateControl并不是 &#34;让&#34;
但是,如果您尝试:
,它可能与桥接的Objective-C枚举案例的表示方式有关。UIControlState.normal = 3
你显然应该得到错误:
这意味着它已被声明(Objective-C)为 readonly 属性。