@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
@import url(/css/cuteeditor.css);
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
@import url(/css/cuteeditor.css);
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

本文转载自 Erica Sadun 的博客

In the dark fetid implementation mists behind the slick city Swift streets lies a secret world where enumerations are merely ints with pretensions. In more objective terms, Swift enums provide a complete and finite ordered listing of the possible members in a fixed collection. They basically come in three flavors.

Basic Enumerations. First, there’s a common variety of “related things” that form a family.

enum Coin {case Heads, Tails}

These basic enumerations provide a fixed vocabulary about possible states you may encounter (if rollValue == .Heads or if collection.contains(.Tails)). Collections with enumerations can contain repetitions. For example, [.Tails, .Tails, .Heads] represents a series of enumeration states, perhaps detailing the history of coin tosses.

Avoid basic enumerations for bit flags as there’s a specific RawOptionSet solution for flags.

Fixed Values. A second flavor of enums offer an associated a raw value. The following example uses natural ordering, starting with 1. Tails’ rawValue is 2.

enum Coin: Int {case Heads = 1, Tails}

These values can be continuous, as in this example, or discrete {case Heads = 5, Tails = 23} but the type, which is declared after the enumeration name, is always homogenous.

You can use other types, such as Strings, but there’s always a one-to-one correspondence between the enumeration and its value. So a .King enumeration may always equate to 12 or “King”. Think of these as a look-up table.

Associated Payloads. And there’s the kind that packs payloads. The most commonly used implementation of these is optionals (case .None, case .Some(T)) but you can build your own as well. Cases can use any types, and those types may include tuples.

enum Coin {case Heads(NSDate, Bool, String); case Tails}

The Dark Underbelly of the Enum

To better understand enumerations, it helps to poke at them with a sharp stick. For obvious reasons, don’t use the following material for production code. Or really for any code. That said, I found this exercise extremely valuable for understanding how enums work.

Enums are typically one byte long.

sizeof(Coin); // 1

If you want to get very very silly, you can build an enumeration with hundreds of cases, in which case the enum takes up 2 or more bytes depending on the minimum bit count needed. If you’re building enumerations with more than 256 cases, you probably should reconsider why you’re using enumerations.

Basic enumerations (the first two cases) are Hashable, that is, they provide an integer hashValue that is unique to each value. Unsurprisingly, the hash values for enumerations start at zero and increase monotonically. (Yes, this is an implementation detail. Alarm bell. Warning blare.)

enum Planets {case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Neptune, Uranus, Pluto} 
print(Planets.Mars.hashValue) // 3
print(Planets.Mercury.hashValue) // 0

Enumerations with basic associated values are also raw representable. The rawValue follows from whatever default or explicit assignment you’ve made. All raw values are of the same type, in this case Int:

enum Foo : Int {case i = 1, j = 5, k = 9}
Foo.j.hashValue // 1
Foo.j.rawValue // 5

Moving Forward

So given these details of how enumerations work:

  • How do you create instances from rawValues?
  • How do you create instances from hashValues?
  • How do you query an enumeration about its members?

I warn you in the strongest possible terms against continuing to read. Tom does not approve.

Creating instances from Raw Values

Okay, I lied. This one, he does approve of. That’s because it’s legal.

enum Foo : Int {case i = 1, j = 5, k = 9}
Foo(rawValue: 5) // .j

You create instances using the built-in constructor, supplying the raw value.

Enhancing Enums

Now we wander into the shadow of the valley of doom, so you should start to fear some evil. Swift is no longer with you, and unsafe bitcasts lie ahead. The goal is to create this protocol, with default implementations that supplies the following features to all enumerations of the first two types.

public protocol EnumConvertible: Hashable {
    init?(hashValue hash: Int)
    static func countMembers() -> Int
    static func members() -> [Self]
}

Building Enums from Hash Values

Since it’s a given that an enumeration is basically an Int8 that stores the hash value, you can build a really simple initializer. Just cast the Int8 that’s initialized with a hash value to the enumeration type.

let member = unsafeBitCast(UInt8(index), Self.self)

This line doesn’t check for safe values, so you probably want to use some sort of check that the value is within the membership limit, and create a failable initializer instead.

internal static func fromHash(
    hashValue index: Int) -> Self {
    let member = unsafeBitCast(UInt8(index), Self.self)
    return member
}
public init?(hashValue hash: Int) {
    if hash >= Self.countMembers() {return nil}
    self = Self.fromHash(hashValue: hash)
}

Once added to the protocol, you can construct an instance from its hash value (countable, starting with 0) and look up its raw value:

Foo(hashValue: 1)!.rawValue // 5

Boom done. And Tom turns away, disapproval writ large upon his face.

Counting Members

The hash-value-based init depends on there being some way to count enumeration members. If you know you’ll always deal with one-byte enumerations, this is super easy. Adding support for two bytes isn’t much harder.

static public func countMembers() -> Int {
    let byteCount = sizeof(self)
    if byteCount == 0 {return 1}
    if byteCount byteCount > 2 {
    fatalError("Unable to process enumeration")}
    let singleByte = byteCount == 1
    let minValue = singleByte ? 2 : 257
    let maxValue = singleByte ? 2 << 8 : 2 << 16
    for hashIndex in minValue..<maxValue {
    switch singleByte {
    case true:
    if unsafeBitCast(UInt8(hashIndex), self).hashValue == 0 {
    return hashIndex
    }
    case false:
    if unsafeBitCast(UInt16(hashIndex), self).hashValue == 0 {
    return hashIndex
    }
    }
    }
    return maxValue
}

This approach uses a simple iteration to construct values until a hashValue look-up fails. It’s pretty brain dead although it knows that 2-byte enums cannot contain fewer than 256 values.

Unfortunately, protocol implementation doesn’t allow you to create storage so you end up re-computing this value all the time (or would if you used this, which you won’t because Tom would not approve).

Enumerating Enumerations

The final goal lies in creating a collection that allows you to enumerate through your enumerations to cover all available cases. For that, you need to return all members.

static public func members() -> [Self] {
    var enumerationMembers = [Self]()
    let singleByte = sizeof(self) == 1
    for index in 0..<Self.countMembers() {
    switch singleByte {
    case true:
    let member = unsafeBitCast(UInt8(index), self)
    enumerationMembers.append(member)
    case false:
    let member = unsafeBitCast(UInt16(index), self)
    enumerationMembers.append(member)
    }
    }
    return enumerationMembers
}

As with the membership count, this is something that would benefit either from being built-in (well, of course), or from implementation that prevents it being computed more than once.

Once you add this, you can perform tasks like “show me a function as it relates to each member of an enumeration”. Although actual sequencing is an illusion — enumeration members may not be built upon any intrinsic sequence semantics — it can be super handy to be able to access items in this way.

Wrap-Up

You can see an example of why this function would be particularly helpful in this gist, which I wrote in response to a post on devforums. Someone was looking for a probability-weighted enum and it was their post that led me to start exploring this whole question.

I gisted my answer here. It is based on a far less elegant solution for collecting members but it showcases why the use-case is valid and compelling.

The entire protocol discussed in this post is at this gist and awaits your feedback, insight, and suggestions. Please tweet or leave comments here because Github doesn’t notify by email.

Finally. Sorry, Tom.

@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);

iOS - Swift Enumerations or how to annoy Tom的更多相关文章

  1. iOS swift的xcworkspace多项目管理(架构思想)

    iOS  swift的xcworkspace多项目管理(架构思想) 技术说明: 今天在这里分享 swift下的 xcworkspace多项目管理(架构思想),能为我们在开发中带来哪些便捷?能为我们对整 ...

  2. iOS Swift 模块练习/swift基础学习

    SWIFT项目练习     SWIFT项目练习2 iOS Swift基础知识代码 推荐:Swift学习使用知识代码软件 0.swift中的宏定义(使用方法代替宏) 一.视图  +控件 1.UIImag ...

  3. ios swift 实现饼状图进度条,swift环形进度条

    ios swift 实现饼状图进度条 // // ProgressControl.swift // L02MyProgressControl // // Created by plter on 7/2 ...

  4. Building gRPC Client iOS Swift Note Taking App

    gRPC is an universal remote procedure call framework developed by Google that has been gaining inter ...

  5. iOS Swift WisdomScanKit图片浏览器功能SDK

    iOS Swift WisdomScanKit图片浏览器功能SDK使用 一:简介      WisdomScanKit 由 Swift4.2版编写,完全兼容OC项目调用. WisdomScanKit的 ...

  6. iOS Swift WisdomScanKit二维码扫码SDK,自定义全屏拍照SDK,系统相册图片浏览,编辑SDK

    iOS Swift WisdomScanKit 是一款强大的集二维码扫码,自定义全屏拍照,系统相册图片编辑多选和系统相册图片浏览功能于一身的 Framework SDK [1]前言:    今天给大家 ...

  7. iOS Swift WisdomHUD 提示界面框架

    iOS Swift WisdomHUD 提示界面框架  Framework Use profile(应用简介) 一:WisdomHUD简介 今天给大家介绍一款iOS的界面显示器:WisdomHUD,W ...

  8. iOS Swift WisdomKeyboardKing 键盘智能管家SDK

    iOS Swift WisdomKeyboardKing 键盘智能管家SDK [1]前言:    今天给大家推荐个好用的开源框架:WisdomKeyboardKing,方面iOS日常开发,优点和功能请 ...

  9. iOS swift项目IM实现,从长连接到数据流解析分析之Socket

    iOS  swift项目IM实现,从长连接到底层数据解析分析之Socket 一:项目简介:  去年开始接手了一个国企移动项目,项目的需求是实现IM即时通讯功能. * 一期版本功能包括了:       ...

随机推荐

  1. BZOJ 3198: [Sdoi2013]spring [容斥原理 哈希表]

    3198: [Sdoi2013]spring 题意:n个物品6个属性,求有多少不同的年份i,j满足有k个属性对应相等 一开始读错题了,注意是对应相等 第i个属性只能和第i个属性对应 容斥一下 \[ 恰 ...

  2. 【模板小程序】循环方阵构造(仿《剑指offer》循环矩阵打印)

    /* 本程序说明: 输入:方阵大小n,输出:n*n的旋转方阵 举例: 当n=2时,输出: 1 2 4 3 当n=4时,输出: 1 2 3 4 12 13 14 5 11 16 15 6 10 9 8 ...

  3. 定时跳转的两种方式(html + javaweb)

    html方式 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...

  4. python爬虫(3)——SSL证书与Handler处理器

    一.SSL证书问题 上一篇文章,我们创建了一个小爬虫,下载了上海链家房产的几个网页.实际上我们在使用urllib联网的过程中,会遇到证书访问受限的问题. 处理HTTPS请求SSL证书验证,如果SSL证 ...

  5. 关于 IO的同步异步间要描述

    IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口. 比如你打开 ...

  6. 配置python虚拟环境Virtualenv及pyenv

    pyenv pyenv 可以让机器安装各种不同版本的python pyenv install --list 查看可以安装的python版本 pyenv versions 查看已安装的python版本 ...

  7. ftp服务器的简单配置使用

    yum install -y vsftpd systemctl start vsftpd   cd /var/ftp/pub/   mkdir 111   touch weifeng.txt     ...

  8. 洛谷P2891 Dining P1402 酒店之王【类二分图匹配】题解+代码

    洛谷P2891 Dining P1402 酒店之王[类二分图匹配]题解+代码 酒店之王 题目描述 XX酒店的老板想成为酒店之王,本着这种希望,第一步要将酒店变得人性化.由于很多来住店的旅客有自己喜好的 ...

  9. 使用PowerDesigner对NAME和COMMENT互相转换

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 在使用PowerDesigner对数据库进行概念模型和物理模型设计时 ...

  10. 一个web应用的诞生(1)--初识flask

    基于flask的web应用的诞生 Flask是一个非常优秀的web框架,它最大的特点就是保持一个简单而易于扩展的小核心,其他的都有用户自己掌握,并且方便替换,甚至,你可以在社区看到众多开源的,可直接用 ...