为什么UIControlState是结构而不是枚举?

时间:2017-09-25 07:05:53

标签: ios swift

我对UIControlState的运行方式感到有些困惑。具体来说,如果我看下面的例子:

sender.setTitle("NewTitle", for: UIControlState.normal) 

据我所知,这为Button(发件人)的正常状态设定了标题。我原以为.normal是UIControlState类型的Enum值,但是后来才知道它是一个带常量的结构。第一个问题:

  1. 如果目的只是为了通过一个州,为什么这个被定义为枚举,其中.normal是其中一个案例?
  2. 其次,当我查看UIStateControl的文档时,我看到的只是"常量的定义,"例如:

    static var normal: UIControlState
    

    第二/第三个问题:

    1. 为什么"常数"用于" var"定义的UIStateControl而不是"让?"

    2. 如何将UIControlState的静态属性定义为" UIControlState?"这不是递归的吗?

2 个答案:

答案 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实例,它是easymedium选项的组合(求和)。

因此:

sender.setTitle("title", for: [.normal, .disabled])


  

为什么&#34;常数&#34;用于&#34; var&#34;定义的UIStateControl并不是   &#34;让&#34;

但是,如果您尝试:

,它可能与桥接的Objective-C枚举案例的表示方式有关。
UIControlState.normal = 3

你显然应该得到错误:

enter image description here

这意味着它已被声明(Objective-C)为 readonly 属性。