引言
先來看看一個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 Protocol
的struct
。是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 OptionSetType
把SetAlgebraType
的接口實現了。這樣當我的HelpOptions
實現OptionSetType
時,調用SetAlgebraType
協議的方法就行了,而不用自己的去實現。這是以前沒有想到的地方。