2017-09-25 30 views
3

我對UIControlState如何操作感到困惑。具體來說,如果我看下面的例子:爲什麼UIControlState是一個Struct而不是Enum?

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

據我所知,這設置按鈕的(發件人)正常狀態的標題。我會期望.normal是UIControlState類型的Enum值,但是卻知道它是一個帶有常量的結構。第一個問題:

  1. 如果目的只是通過一個狀態,爲什麼不把它定義爲一個enum作爲其中一個例子?

其次,當我看爲UIStateControl的文檔,我看到的是定義 「常量」,例如:

static var normal: UIControlState 

第二/第三問題:

  • 爲什麼UIStateControl的」常量「用」var「而不是」let?「來定義

  • UIControlState的靜態屬性如何定義爲「UIControlState?」類型?這不是遞歸嗎?

  • +0

    我不知道這個,但如果你看到結構'公共結構UIControlState:OptionSet''OptionSet'是RowRepresntable,所以。正常是好的,可能@ Paulw11可能會在這幫助 –

    +0

    @ Paulw11這不是由於Obj-C的任何限制;用'NS_ENUM'宏定義的枚舉以'enum's的形式導入到Swift中。這純粹是由於「UIControlState」基本上不是'enum';這是一個選項集。 – Hamish

    回答

    4

    爲什麼UIControlState一個結構,而不是一個枚舉?

    UIControlState根本不枚舉。枚舉是一個「OR」類型。

    enum Foo { 
        case a, b, c 
    } 
    
    var f = Foo.a 
    f = .b 
    f = .c 
    

    因此,在上述例子中,f可容納.a.b.c

    但是,這不是與UIControlState的情況;這是一個選項集。選項集可以包含一組一個或多個案例。因此,它是一個「和」類型,和我們平時用struct是符合OptionSet協議執行。

    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 
    

    這不是很準確的定義。該UIControlState聲明中自動生成的斯威夫特頭看起來是這樣的:

    ​​

    你會注意到{ get }末。這意味着它們只是只讀屬性。它們是如何實際實現的(因爲let常量,var只讀計算屬性等)是純粹的實現細節。

    在這種情況下,UIControlState UIKit中被定義與NS_OPTIONS宏,它夫特imports in as anOptionSet貼合結構與每個選項值是一個靜態只讀屬性。

    UIControlState的靜態屬性如何定義爲類型「UIControlState?」?這不是遞歸嗎?

    不,它不是遞歸的。請記住,他們是static性質,因此不外乎命名空間,UIControlState全局變量更多的(他們甚至不需要有存儲,他們可以計算,但是再一次這是一個實現細節)。

    如果他們是實例存儲的屬性,那麼它確實是遞歸的。但他們不是。

    1

    爲什麼UIControlState一個結構,而不是一個枚舉?

    因爲UIControlEvents是關係到UIKit框架已經使用Objective-C的建成,意味着它無關,與雨燕枚舉。


    如果目的是爲了只傳遞一個狀態,爲什麼不這樣定義爲 枚舉與作爲。中性的情況嗎?

    儘管如此,UIControlEvents結構符合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通常是(2的兩個獨特的權力1, 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符合OptionSet的結構

    但是等等!爲什麼要使用符合OptionSet協議而不是枚舉的結構?

    除了什麼提到有關的編程語言之間的差,枚舉是用於一次一個單個值之一表示,但OptionSet結構可以在一個單一的值組合值的表示,聽起來很混亂?考慮以下幾點:

    let combinedOption: CustomOptions = [.easy, .medium] 
    print(combinedOption) // CustomOptions(rawValue: 3) 
    

    在第一次看,[.easy, .medium]可能會非常棘手,它看起來像一個數組,但它不是!實際上它是一個單一的CustomOptions實例,它是easymedium選項的組合(總和)。

    這樣:

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


    爲什麼在 「常數」 爲UIStateControl與 「VAR」 定義,而不是 「讓?」

    這可能涉及到的橋接Objective-C的枚舉情況下,表示應該如何,但是,如果你想嘗試:

    UIControlState.normal = 3 
    

    很顯然你應該得到的錯誤:

    這意味着它已被宣佈(目標C),其爲只讀屬性。

    +0

    感謝您的解釋,你知道爲什麼'靜態變量normal:UIControlState'?而不是'讓' –

    +0

    @JonSnow答案更新:) –

    +0

    請參閱[我上面的評論](https://stackoverflow.com/questions/46399384/why-is-uicontrolstate-a-struct-and-not-an-enum/ 46405114#comment79767538_46399384);在Obj-C中定義'UIControlState'的事實與爲什麼它沒有作爲enum導入到Swift中沒有任何關係。純粹是因爲'UIControlState'基本上不是'enum'。 – Hamish

    相關問題