引言
先來看看一個(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 Protocol的struct。是OptionSetType這個(gè)協(xié)議賦予了其這樣的特征表現(xiàn)。那么我們來看看OptionSetType的結(jié)構(gòu)。

圖里的每個(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 OptionSetType把SetAlgebraType的接口實(shí)現(xiàn)了。這樣當(dāng)我的HelpOptions實(shí)現(xiàn)OptionSetType時(shí),調(diào)用SetAlgebraType協(xié)議的方法就行了,而不用自己的去實(shí)現(xiàn)。這是以前沒有想到的地方。