Swift - OptionSetType

引言

先來看看一個(gè)UIView動(dòng)畫在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)

我們可以發(fā)現(xiàn),在Objective-C中傳入的options是UIViewAnimationOptionCurveEaseInOut|UIViewAnimationOptionAllowUserInteractio,是用的傳統(tǒng)的|(或)操作;而Swift里是[.CurveEaseInOut,.AllowUserInteraction],這個(gè)乍看之下很像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是實(shí)現(xiàn)OptionSetType Protocolstruct。是OptionSetType這個(gè)協(xié)議賦予了其這樣的特征表現(xiàn)。那么我們來看看OptionSetType的結(jié)構(gòu)。

OptionSetType 樹

圖里的每個(gè)方框都是協(xié)議,虛線代表協(xié)議的繼承關(guān)系。
下面我們來一個(gè)個(gè)介紹它們

Equatable Protocol

實(shí)現(xiàn)Equatable可以通過重載==!=操作符來判斷相等關(guān)系。

ArrayLiteralConvertible Protocol

實(shí)現(xiàn)此協(xié)議的類型能夠通過類似于[value1,value2]這種聲明Array的方式來進(jìn)行聲明。
例如:

struct Poker : ArrayLiteralConvertible, CustomStringConvertible {
    var cards = [String]()
    // ArrayLiteralConvertible 的構(gòu)造器接口
    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

通過實(shí)現(xiàn)ArrayLiteralConvertible協(xié)議,然后重寫init(arrayLiteral elements: Element...)構(gòu)造器,就能夠像創(chuàng)建數(shù)組一樣來創(chuàng)建這個(gè)被我稱為Poker的結(jié)構(gòu)體了。

UIViewAnimationOptions正是因?yàn)?code>OptionSetType的繼承樹里有ArrayLiteralConvertible協(xié)議,才使我們能夠像創(chuàng)建數(shù)組一樣來創(chuàng)建它。

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

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

SetAlgebraType Protocol

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

RawRepresentable Protocol

這個(gè)協(xié)議很簡單,只有幾句代碼:

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

要求實(shí)現(xiàn)RawRepresentable的類型要有一個(gè)rawValue,然后還有給出對應(yīng)的構(gòu)造器,就OK了。

應(yīng)用 OptionSetType

到實(shí)戰(zhàn)部分了,現(xiàn)在有三種求救方式分別為打110,119和120, 當(dāng)我們求救時(shí),可以打任意打三個(gè)電話的任何一個(gè)或多個(gè)。下面是代碼

struct HelpOptions : OptionSetType {
    var rawValue = 0  // 因?yàn)镽awRepresentable的要求
    
    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("護(hù)士姐姐來啦")  }

HelpOptions的結(jié)構(gòu)很清晰易懂,每個(gè)不同的的選項(xiàng)都是HelpOptions的一個(gè)靜態(tài)屬性,并且都有一個(gè)rawValue來對應(yīng)值。
我們只用通過contains等代數(shù)操作來判斷就知道到底需要打電話給誰了。

而所有代數(shù)相關(guān)的邏輯操作和判斷都由OptionSetType的extension做了,而我們什么都不用管。真是感嘆OptionSetType真是個(gè)好人??!

總結(jié)

今天很認(rèn)真的看了OptionSetType相關(guān)的結(jié)構(gòu)和使用方法,真心發(fā)現(xiàn)Swift的編程范式和Objective-C 還是蠻大。
我發(fā)現(xiàn)的一點(diǎn)是,OptionSetType繼承了SetAlgebraType(protocol 的繼承)。然后直接通過extension OptionSetTypeSetAlgebraType的接口實(shí)現(xiàn)了。這樣當(dāng)我的HelpOptions實(shí)現(xiàn)OptionSetType時(shí),調(diào)用SetAlgebraType協(xié)議的方法就行了,而不用自己的去實(shí)現(xiàn)。這是以前沒有想到的地方。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容