Swfit 2.0之選項(xiàng)集合(Option Sets)

Swift 2.0增加了一個(gè)很厲害的新特性,其名為選項(xiàng)集合(Option Sets),這個(gè)特性讓我們可以用炒雞簡(jiǎn)單的方式來對(duì)位掩碼進(jìn)行操作。

位掩碼

如果你從未使用過位掩碼,你可能會(huì)問,這到底是什么鬼?
請(qǐng)容我來稍微解釋一下。

假設(shè)我們?cè)趯懸粋€(gè)角色扮演的游戲(比如說傳奇,嗯?),游戲的角色可能擁有各種裝備,比如盔甲,劍以及頭盔等等,你的第一反應(yīng)可能是用 Bool 屬性來對(duì)各種裝備進(jìn)行表示,類似下面這樣:

var hasSword = true  // 裁決之杖
var hasArmor = true  // 戰(zhàn)神寶甲
var hasHelmet = false  // 圣戰(zhàn)頭盔

其實(shí),還可以有另一種做法,就是定義一個(gè)整數(shù)并使用它的比特位來進(jìn)行表示。由于每個(gè)比特位只能存儲(chǔ) 0 或者 1,可以使用它來對(duì)每個(gè)裝備進(jìn)行表示,這就是所謂的位掩碼。如下圖所示:

位掩碼

遠(yuǎn)古時(shí)期的位掩碼操作方法

其實(shí)操作位掩碼對(duì) Swift 來說也不是什么新鮮事了,早在 Swift 1.2 就有一個(gè) RawOptionSetType 類型?用來定義位掩碼。不過由于其定義方法過于繁瑣,甚至有點(diǎn)反人類,在這里就不進(jìn)行展示了。如果實(shí)在有興趣,可以自行 Google,或者直接上官網(wǎng)。

這里只稍微講一下使用定義好的位掩碼:

let inventory: Inventory = .Sword | .Armor
if inventory & .Sword != nil {
    println("屠龍?jiān)谑?,天下我?)
}

如果對(duì)位操作符用得比較少,這種代碼看起來的確會(huì)令人比較頭疼。如果代碼更加復(fù)雜,狀態(tài)更多的話,我們可能得花更多的時(shí)間來理解這段代碼到底是在進(jìn)行什么操作。

新型的位掩碼操作方法

在 Swift 2.0 的新時(shí)代,位掩碼的操作方式大大改善了,只因它推出了一個(gè)新的 OptionSetType 類型。

要定義位掩碼相當(dāng)簡(jiǎn)單,只需要定義一個(gè)結(jié)構(gòu)體,并讓它遵守 OptionSetType 協(xié)議就行了:

struct Inventory: OptionSetType {
    let rawValue: Int
    static let Sword = Inventory(rawValue: 1)
    static let Armor = Inventory(rawValue: 1 << 1)
    static let Helmet = Inventory(rawValue: 1 << 2)
}

這里聲明了一個(gè) rawValue 的屬性,這個(gè) Int 類型的屬性就是用來存儲(chǔ)所有要表示的比特位。同時(shí)還使用位移操作定義了三個(gè)類型,使用位移操作可以方便地指定整數(shù)中的哪個(gè)位用來表示哪個(gè)屬性,而不用手動(dòng)進(jìn)行計(jì)算。

定義好類型之后,我們可以像使用普通的 Set 集合類型一樣來使用它,Swift 在底層會(huì)自己使用位掩碼來處理,作為使用者,我們不必操心:

var inventory: Inventory = [.Sword, .Shield]
if inventory.contains(.Shield) {
    print("屠龍?jiān)谑?,天下我?)
}

這段代碼與上面一小節(jié)的代碼實(shí)現(xiàn)了相同的功能。但是這段代碼看起來更加簡(jiǎn)潔明了,同時(shí)寫起來也更加順手,我們直接使用了高層的 API 來對(duì)底層的比特位進(jìn)行操作,這種好處是顯而易見的。

Show Me The Code

下面我們使用一個(gè)小 Demo 來進(jìn)行下實(shí)際操作。

假設(shè)我們想用一個(gè)類型來表示一個(gè)程序員的技能樹,類似他有沒有自己的個(gè)人博客,有沒有 GitHub,以及是否有 StackOverflow 的帳號(hào)。

打開 Xcode 7,并新建一個(gè) Playground,定義技能類型:

struct Skills: OptionSetType {
    let rawValue: Int
    static let LOL = Skills(rawValue: 1)
    static let GitHub = Skills(rawValue: 1 << 1)
    static let PersonalBlog = Skills(rawValue: 1 << 2)
    static let StackOverflow = Skills(rawValue: 1 << 3)
}

再定義一個(gè)程序員類型:

struct Programmer {
    var possibleSkills: Skills = [.LOL]
    
    mutating func quitLOL() {
        if possibleSkills.contains(.LOL) {
            print("不要再玩了,快去寫代碼吧")
            possibleSkills.subtractInPlace(.LOL)
        }
    }
    
    mutating func signUpStackOverflow() {
        if !possibleSkills.contains(.StackOverflow) {
            possibleSkills.unionInPlace(.StackOverflow)
            print("StackOverflow 帳號(hào)注冊(cè)完畢,可以上去提問題了")
        } else {
            print("你已經(jīng)有 StackOverflow 賬號(hào)了,先去回答幾個(gè)問題吧")
        }
    }
    
    mutating func signUpGitHub() {
        if !possibleSkills.contains(.GitHub) {
            possibleSkills.unionInPlace(.GitHub)
            print("GitHub 帳號(hào)注冊(cè)完畢,快去騙 star 吧.")
        } else {
            print("你已經(jīng)有 GitHub 了,請(qǐng)不要重復(fù)注冊(cè).")
        }
    }
}

首先,定義一個(gè) possibleSkills 屬性,用來表示這個(gè)程序員擁有的技術(shù)(現(xiàn)在這貨很廢材,就只會(huì) LOL),注意我們把這個(gè)屬性定義成了 var 類型,因?yàn)橹笪覀冃枰淖兯?/p>

接著,我們定義了三個(gè)方法,由于要在方法里修改結(jié)構(gòu)體中的屬性,所以都得加上 mutating 修飾符。三個(gè)方法里都使用了 Set 集合的方法來對(duì)程序員的技能進(jìn)行改變。

接著,來實(shí)際使用下這個(gè)定義好的類型:

var programmer = Programmer()
programmer.quitLOL()
programmer.signUpGitHub()
programmer.signUpStackOverflow()

這個(gè)代碼很簡(jiǎn)單,先實(shí)例化一個(gè)程序員,然后讓他戒掉了 LOL,接著讓他去注冊(cè)了 GitHub 跟 StackOverflow。這貨要好好學(xué)習(xí),然后當(dāng)上總經(jīng)理,出任 CEO 了,迎娶白富美,從此走向人生巔峰,想想還是有點(diǎn)小激動(dòng)啊。是不是很勵(lì)志呢,嗯?

完整的 Playgroud 代碼可以在 我的GitHub 上下載到。

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

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,284評(píng)論 4 61
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 12,391評(píng)論 6 13
  • 不知道你會(huì)不會(huì)跟我一樣很容易舍不得。小時(shí)候,有時(shí)親戚到我家住幾天,到離開那天,我都會(huì)很難受。經(jīng)常放的牛被家里賣掉了...
    唔哩君閱讀 985評(píng)論 0 0
  • 從2月份就張羅著買門票,定酒店,訂車票。終于所有事都敲定了,只等五月一號(hào)了。4月26號(hào)領(lǐng)導(dǎo)宣布財(cái)務(wù)科不準(zhǔn)請(qǐng)假,月底...
    裹著項(xiàng)鏈的一個(gè)我閱讀 309評(píng)論 0 0
  • 在我很小很小的時(shí)候 南方是我遙遠(yuǎn)的夢(mèng)想 夢(mèng)想里有蔚藍(lán)的大海 大海里躺著火紅火紅的太陽 太陽讓懵懂的我滿懷期望 長(zhǎng)大...
    年輕的風(fēng)閱讀 378評(píng)論 1 2

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