Swift - OptionSetType

引言

先來看看一個UIView動畫在Objective-C和Swift里面分別是怎么寫的。

[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteraction animations:^{
    // ... Animations
} completion: nil];
UIView.animateWithDuration(0.3, delay: 0, options: [.CurveEaseInOut,.AllowUserInteraction], animations: { () -> Void in
    // ... Animations
}, completion: nil)

我們可以發現,在Objective-C中傳入的options是UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteractio,是用的傳統的|(或)操作;而Swift里是[.CurveEaseInOut,.AllowUserInteraction],這個乍看之下很像Array的東西又是什么呢?

OptionSetType

UIViewAnimationOptions的聲明是這樣的:

@available(iOS 4.0, *)
public struct UIViewAnimationOptions : OptionSetType {
    public init(rawValue: UInt)
    
    public static var LayoutSubviews: UIViewAnimationOptions { get }
    public static var AllowUserInteraction: UIViewAnimationOptions { get } // turn on user interaction while animating
    public static var BeginFromCurrentState: UIViewAnimationOptions { get } // start all views from current value, not initial value
    //...... 還有很多屬性
}

UIViewAnimationOptions是實現OptionSetType Protocolstruct。是OptionSetType這個協議賦予了其這樣的特征表現。那么我們來看看OptionSetType的結構。

OptionSetType 樹

圖里的每個方框都是協議,虛線代表協議的繼承關系。
下面我們來一個個介紹它們

Equatable Protocol

實現Equatable可以通過重載==,!=操作符來判斷相等關系。

ArrayLiteralConvertible Protocol

實現此協議的類型能夠通過類似于[value1,value2]這種聲明Array的方式來進行聲明。
例如:

struct Poker : ArrayLiteralConvertible, CustomStringConvertible {
    var cards = [String]()
    // ArrayLiteralConvertible 的構造器接口
    init(arrayLiteral elements: String...) {
        for card in elements {
            cards.append(card)
        }
    }
    var description: String {
        var content = "My cards are "
        for card in self.cards {
            content += card
        }
        return content
    }
}
// How to use
let myPocker:Poker = ["2","4","3","J","A"]
print(myPocker)       // 輸出:My  cards are 243JA

通過實現ArrayLiteralConvertible協議,然后重寫init(arrayLiteral elements: Element...)構造器,就能夠像創建數組一樣來創建這個被我稱為Poker的結構體了。

UIViewAnimationOptions正是因為OptionSetType的繼承樹里有ArrayLiteralConvertible協議,才使我們能夠像創建數組一樣來創建它。

另外,還有Swift還提供了幾個類似ArrayLiteralConvertible的接口:

  • BooleanLiteralConvertible
  • DictionaryLiteralConvertible
  • ExtendedGraphemeClusterLiteralConvertible
  • FloatLiteralConvertible
  • NilLiteralConvertible
  • IntegerLiteralConvertible
  • StringLiteralConvertible
  • UnicodeScalarLiteralConvertible

SetAlgebraType Protocol

SetAlgebraType為實現該協議的類型提供代數操作(交集,并集,異或,插入,刪除等)。
OptionSetType在confirm SetAlgebraType協議后,就直接通過extension擴展實現了相對的功能,因此在真實的使用場景中,我們只需要調用代數操作結果,而不用關心具體實現。

RawRepresentable Protocol

這個協議很簡單,只有幾句代碼:

public protocol RawRepresentable {
    typealias RawValue
    public init?(rawValue: Self.RawValue)
    public var rawValue: Self.RawValue { get }
}

要求實現RawRepresentable的類型要有一個rawValue,然后還有給出對應的構造器,就OK了。

應用 OptionSetType

到實戰部分了,現在有三種求救方式分別為打110,119和120, 當我們求救時,可以打任意打三個電話的任何一個或多個。下面是代碼

struct HelpOptions : OptionSetType {
    var rawValue = 0  // 因為RawRepresentable的要求
    
    static var Call110 = HelpOptions(rawValue: 1 << 0)
    static var Call119 = HelpOptions(rawValue: 1 << 1)
    static var Call120 = HelpOptions(rawValue: 1 << 2)
}
// How to use
let fireNeedHelp: HelpOptions = [HelpOptions.Call120,HelpOptions.Call119]
//   let killNeedHelp: HelpOptions = [HelpOptions.Call120,HelpOptions.Call110]
        
if fireNeedHelp.contains(.Call110) {  print("警察叔叔來啦")  }
if fireNeedHelp.contains(.Call119) {  print("消防員叔叔來啦")  }
if fireNeedHelp.contains(.Call120) {  print("護士姐姐來啦")  }

HelpOptions的結構很清晰易懂,每個不同的的選項都是HelpOptions的一個靜態屬性,并且都有一個rawValue來對應值。
我們只用通過contains等代數操作來判斷就知道到底需要打電話給誰了。

而所有代數相關的邏輯操作和判斷都由OptionSetType的extension做了,而我們什么都不用管。真是感嘆OptionSetType真是個好人啊!

總結

今天很認真的看了OptionSetType相關的結構和使用方法,真心發現Swift的編程范式和Objective-C 還是蠻大。
我發現的一點是,OptionSetType繼承了SetAlgebraType(protocol 的繼承)。然后直接通過extension OptionSetTypeSetAlgebraType的接口實現了。這樣當我的HelpOptions實現OptionSetType時,調用SetAlgebraType協議的方法就行了,而不用自己的去實現。這是以前沒有想到的地方。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容