Swfit 2.0之选项集合(Option Sets)

Swift 2.0增加了一个很厉害的新特性,其名为选项集合(Option Sets),这个特性让我们可以用炒鸡简单的方式来对位掩码进行操作。

位掩码

如果你从未使用过位掩码,你可能会问,这到底是什么鬼?
请容我来稍微解释一下。

假设我们在写一个角色扮演的游戏(比如说传奇,嗯?),游戏的角色可能拥有各种装备,比如盔甲,剑以及头盔等等,你的第一反应可能是用 Bool 属性来对各种装备进行表示,类似下面这样:

var hasSword = true  // 裁决之杖
var hasArmor = true  // 战神宝甲
var hasHelmet = false  // 圣战头盔

其实,还可以有另一种做法,就是定义一个整数并使用它的比特位来进行表示。由于每个比特位只能存储 0 或者 1,可以使用它来对每个装备进行表示,这就是所谓的位掩码。如下图所示:

位掩码

远古时期的位掩码操作方法

其实操作位掩码对 Swift 来说也不是什么新鲜事了,早在 Swift 1.2 就有一个 RawOptionSetType 类型�用来定义位掩码。不过由于其定义方法过于繁琐,甚至有点反人类,在这里就不进行展示了。如果实在有兴趣,可以自行 Google,或者直接上官网。

这里只稍微讲一下使用定义好的位掩码:

let inventory: Inventory = .Sword | .Armor
if inventory & .Sword != nil {
    println("屠龙在手,天下我有")
}

如果对位操作符用得比较少,这种代码看起来的确会令人比较头疼。如果代码更加复杂,状态更多的话,我们可能得花更多的时间来理解这段代码到底是在进行什么操作。

新型的位掩码操作方法

在 Swift 2.0 的新时代,位掩码的操作方式大大改善了,只因它推出了一个新的 OptionSetType 类型。

要定义位掩码相当简单,只需要定义一个结构体,并让它遵守 OptionSetType 协议就行了:

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)
}

这里声明了一个 rawValue 的属性,这个 Int 类型的属性就是用来存储所有要表示的比特位。同时还使用位移操作定义了三个类型,使用位移操作可以方便地指定整数中的哪个位用来表示哪个属性,而不用手动进行计算。

定义好类型之后,我们可以像使用普通的 Set 集合类型一样来使用它,Swift 在底层会自己使用位掩码来处理,作为使用者,我们不必操心:

var inventory: Inventory = [.Sword, .Shield]
if inventory.contains(.Shield) {
    print("屠龙在手,天下我有")
}

这段代码与上面一小节的代码实现了相同的功能。但是这段代码看起来更加简洁明了,同时写起来也更加顺手,我们直接使用了高层的 API 来对底层的比特位进行操作,这种好处是显而易见的。

Show Me The Code

下面我们使用一个小 Demo 来进行下实际操作。

假设我们想用一个类型来表示一个程序员的技能树,类似他有没有自己的个人博客,有没有 GitHub,以及是否有 StackOverflow 的帐号。

打开 Xcode 7,并新建一个 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)
}

再定义一个程序员类型:

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 帐号注册完毕,可以上去提问题了")
        } else {
            print("你已经有 StackOverflow 账号了,先去回答几个问题吧")
        }
    }
    
    mutating func signUpGitHub() {
        if !possibleSkills.contains(.GitHub) {
            possibleSkills.unionInPlace(.GitHub)
            print("GitHub 帐号注册完毕,快去骗 star 吧.")
        } else {
            print("你已经有 GitHub 了,请不要重复注册.")
        }
    }
}

首先,定义一个 possibleSkills 属性,用来表示这个程序员拥有的技术(现在这货很废材,就只会 LOL),注意我们把这个属性定义成了 var 类型,因为之后我们需要改变它。

接着,我们定义了三个方法,由于要在方法里修改结构体中的属性,所以都得加上 mutating 修饰符。三个方法里都使用了 Set 集合的方法来对程序员的技能进行改变。

接着,来实际使用下这个定义好的类型:

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

这个代码很简单,先实例化一个程序员,然后让他戒掉了 LOL,接着让他去注册了 GitHub 跟 StackOverflow。这货要好好学习,然后当上总经理,出任 CEO 了,迎娶白富美,从此走向人生巅峰,想想还是有点小激动啊。是不是很励志呢,嗯?

完整的 Playgroud 代码可以在 我的GitHub 上下载到。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,934评论 6 13
  • 不知道你会不会跟我一样很容易舍不得。小时候,有时亲戚到我家住几天,到离开那天,我都会很难受。经常放的牛被家里卖掉了...
    唔哩君阅读 876评论 0 0
  • 从2月份就张罗着买门票,定酒店,订车票。终于所有事都敲定了,只等五月一号了。4月26号领导宣布财务科不准请假,月底...
    裹着项链的一个我阅读 283评论 0 0
  • 在我很小很小的时候 南方是我遥远的梦想 梦想里有蔚蓝的大海 大海里躺着火红火红的太阳 太阳让懵懂的我满怀期望 长大...
    年轻的风阅读 346评论 1 2