枚举

枚举

枚举定义了一组通用类型的相互有关系的值,在你的代码中可以使用枚举值做到类型安全。
如果你熟悉C语言,你会知道C语言的枚举给每个枚举名字分配了一个整型数字。Swift的枚举更加灵活,不必给每个枚举成员指定值。字符串、字符、整型、浮点型都可以作为初始值(raw Value)给一个枚举的成员赋值。

或者,枚举成员可以被指定任何类型的联合值而且枚举成员的值类型可以各不相同,像其他语言中的union或者variant一样。你可以定义一组关联的成员作为一个枚举的一部分,它们各自的值类型可以各不相同。

Swift中的枚举是第一类型。枚举具有了一些传统上只有类(class)才有的特性,比如计算过的属性(computed properties)提供当前值的附加属性、比如实例方法(nstance methods)提供和枚举值相关的功能。枚举同样可以定义初始化函数,来提供一个成员的初始值;可以被扩展功能;可以遵循协议(protocol)来提供标准功能。
枚举的这些功能可以参见:Properties、Methods、Initialization、Extensions和Protocols章节。

枚举语法

使用enum关键字定义枚举,枚举的名字之后是一对花括号,其中是它的内容:

​enum​ ​SomeEnumeration​ {
​ ​// enumeration deFinition goes here
​}

这里有个例子,定义了罗盘中的4个主要点:

​enum​ ​Compasspoint​ {
​ ​case​ ​north
​ ​case​ ​South
​ ​case​ ​East
​ ​case​ ​West
​}

定义在枚举中的值(north,south,East,West)是那个枚举的成员值(或者成员)。case关键字表示一个新的成员被定义了。
NOTE
和C语言和OC不同,在创建时,Swift的枚举成员不被指定一个默认的整型数值。在上面的CompasPoint例子中,north、South、East和West不是默认被赋值0、1、2和3。实际上,不同的枚举成员可以选择自己的值类型,在Compasspoint枚举中就可以显示的定义。

多成员值可以在一行定义,它们之间用逗号分隔:

enum​ ​Planet​ {
​ ​case​ ​Mercury​,​Venus​,​Earth​,​Mars​,​Jupiter​,​Saturn​,​Uranus​,​Neptune
​}

每个枚举都定义了一个新的类型。像Swift中的其他类型一样,他们的名字(比如Compasspoint和Planet)需要首字母大写。使用单数要比复数好,阅读起来更容易:
​var​ ​directionToHead​ = ​Compasspoint​.​West
当directionToHead被枚举Compasspoint其中的一个值初始化的时候,它的类型就被推断出来了。一旦directionToHead被定义成了Compasspoint,你可以给它设置另一个Compasspoint 中的值,下面是使用一个点号的简写方式:
directionToHead​ = .​East
directionToHead 的类型已知后,所以可以在赋值的时候舍掉它的类型。当枚举类型明确的时候,这样写带来更好的可读性。

在Switch语句中匹配枚举类型

你可以使用switch语句匹配单个的枚举内容:

directionToHead​ = .​South
​switch​ ​directionToHead​ {
​case​ .​north​:
​ ​println​(​"Lots of planets have a north"​)
​case​ .​South​:
​ ​println​(​"Watch out for penguins"​)
​case​ .​East​:
​ ​println​(​"Where the sun rises"​)
​case​ .​West​:
​ ​println​(​"Where the skies are blue"​)
​}
​// prints "Watch out for penguins"

你可以这样解读上面的代码:
判断一下directionToHead的值。如果等于.north,打印“Lots of palnets have a north”;如果等于.south,打印“Watch out for penguins”,以此类推。
和控制流一章描述的一样,switch语句的分支必须涵盖枚举的所有内容。比如如果.West被省略,那么代码不能被编译通过,因为它没有判断枚举Compasspoint成员列表中的每一项。这个设置避免了因为疏忽造成的遗漏。
如果没有合适的case对应枚举中的每一个成员,你可以用default case 涵盖剩余的:

​let​ ​somePlanet​ = ​Planet​.​Earth
​switch​ ​somePlanet​ {
​case​ .​Earth​:
​ ​println​(​"Mostly harmless"​)
​default​:
​ ​println​(​"Not a safe place for humans"​)
​}
​// prints "Mostly harmless"

联合数值(Associated Values)

上面的内容展示了一个枚举的成员是如何被定义类型和值的。你可以设置一个常量或变量给Planet.Earth,稍后可以检查它的值。然而有时单独给枚举的每个成员存储联合数值更有必要。这使得你可以存储附加的定制信息连同枚举的成员值一起,在使用枚举成员的值的时候同时可以使用这些附加信息。
你可以定义枚举来存储任何给定类型的联合数值,而且每个枚举成员的联合数值的类型可以各不相同。枚举的这点和其他语言中的discriminated unions、tagged unions,、variants类似。

举个例子,设想一下库存跟踪系统中,跟踪一个货品可以根据两种不同的条码。有些货品贴了1D的UPC-A格式的条码,这种格式使用0到9的数字。每个条码有一个“数字系统”码,跟随一个五位的“制造商码”和一个五位的“产品代码”,其后的是一个“校验”码(为了保证条码被正确的扫描):

另外的货品使用了2D、QR格式的条码,这个格式可以使用任意 ISO 8859-1的字符,最长可以使用2953个字符:

方便起见,在库存追踪系统中,使用包括4个整型的元组存储UPC-A类型的条码,使用一个字符串存储QR类型的条码。
Swift中,一个货品条码的枚举(包含两种不同条码型)可以这样定义:

enum​ ​Barcode​ {
​ ​case​ ​UPCA​(​Int​,​Int​,​Int​)
​ ​case​ ​QRCode​(​String​)
​}

上面代码可以这样解读:
定义一个枚举类型叫做Barcode,它同时包括一个值UPCA(联合数值类型:(Int,Int,Int))和另一个值QRCode (联合数据类型:String)。
这个定义没提供任何实际的Int和String值,它只是定义了联合数值的类型(Barcode常量和变量等于Barcode.UPCA或者Barcode.QRCode时,可以存储的类型)。
新条码可以是上面两种中的任意一个:
var​ ​productBarcode​ = ​Barcode​.​UPCA​(​8​,​85909​,​51226​,​3​)
这个例子创建了一个新变量叫做productBarcode,将一个Barcode.UPCA(联合数值元组是(8,85909,51226,3)) 的值赋值给了它。
同样的产品可以用另外一个类型的条码赋值:
​productBarcode​ = .​QRCode​(​”ABCDEFGHIJKLMnop”​)
这时,初始的Barcode.UPCA和它的整型值被一个新的Barcode.QRCode和它的字符串替换。Barcode的常量或者变量可以存储.UPCA或者.QRCode(随同他们的联合数值),但是同时只能选择其中一个。
不同的条码类型同样可以使用switch语句,像前面一样。这次,联合数值可以作为switch语句的一部分被解析出来。在case体内,你可以将每个联合数值的内容作为常量(使用let前缀)或者变量(使用var前缀)解析:

switch​ ​productBarcode​ {
​case​ .​UPCA​(​let​ ​numberSystem​,​let​ ​manufacturer​,​let​ ​product​,​let​ ​check​):
​ ​println​(​"UPC-A: ​\(​numberSystem​)​,​\(​manufacturer​)​,​\(​product​)​,​\(​check​)​."​)
​case​ .​QRCode​(​let​ ​productCode​):
​ ​println​(​"QR code: ​\(​productCode​)​."​)
​}
​// prints "QR code: ABCDEFGHIJKLMnop."

如果一个枚举成员的所有的联合数值被当作常量(或者变量)解析,你可以在成员的名字前使用let(或者var)标记,这样更加简洁:

switch​ ​productBarcode​ {
​case​ ​let​ .​UPCA​(​numberSystem​,​manufacturer​,​product​,​check​):
​ ​println​(​"UPC-A: ​\(​numberSystem​)​,​\(​check​)​."​)
​case​ ​let​ .​QRCode​(​productCode​):
​ ​println​(​"QR code: ​\(​productCode​)​."​)
​}
​// prints "QR code: ABCDEFGHIJKLMnop."

原始值(Raw Values)

上面条码的例子展示了枚举的成员如何定义不同类型的联合数值。作为联合数值的一个替代,枚举成员可以有一个预先指定的值(叫做raw values),前提是他们的类型一致。
这里有一个例子,将ASCII码的原始值存储在枚举成员里面:

enum​ ​ASCIIControlCharacter​: ​Character​ {
​ ​case​ ​Tab​ = ​"\t"
​ ​case​ ​LineFeed​ = ​"\n"
​ ​case​ ​CarriageReturn​ = ​"\r"
​}

这里,枚举被叫做ASCIIControlCharacter ,它被定义为字符类型,被赋值为一些ASCII码的控制字符。字符在 Strings and Characters一章有描述。
记得,原始值和联合数值不是一会儿事儿。原始值在定义枚举的时候就被预先设置了值,就像上面的三个ASCII码一样。一个特定枚举成员的原始值始终是一样的。联合数值在你创建了一个枚举的常量或者变量时才被赋值,而且每次你都可以给他不同的值。

原始值的类型可以是字符串、字符、整型或者浮点型。在枚举类型 定义中,每个原始值必须保证唯一性。当整数作为原始值时,如果有枚举成员没有给出值,那么就采用自增。
下面是前文Planet枚举的一个精简版本,给出了每个行星距离太阳的距离原始排序参考值:

enum​ ​Planet​: ​Int​ {
​ ​case​ ​Mercury​ = ​1​,​Neptune
​}

自增意味着Planet.Venus的原始值是2,以此类推。
访问一个枚举成员的原始值采用他的rawVlaue属性:

let​ ​earthsOrder​ = ​Planet​.​Earth​.​rawValue
​// earthsOrder is 3

依据原始值初始化
如果你使用初始值定义了一个枚举,实际上是得到了一个构造函数,这个构造函数参数类型是原始值类型(一个叫做rawValue的参数),返回值要么是个枚举的成员要么是nil。你可以使用这种方式尝试构造一个枚举的引用。

下面使用天王星(Uranus)的原始值7得到它的引用:

let​ ​possiblePlanet​ = ​Planet​(​rawValue​: ​7​)
​// possiblePlanet is of type Planet? and equals Planet.Uranus

然而并不是所有的整型值都能找到一个匹配的行星。因此,原始值初始化方式始终返回一个枚举成员的可选类型。这个例子中,posssiblePlanet的类型是Planet?或者可选Planet。
NOTE
原始值初始化是一个可以失败的构造函数,因为它不是每次都能返回一个枚举成员。更多信息参见 Failable Initializers 一节。

如果你尝试根据9去找一个行星,原始值初始化返回的可选Planet的值将是nil:

if​ ​let​ ​somePlanet​ = ​Planet​(​rawValue​: ​positionToFind​) {
​ ​switch​ ​somePlanet​ {
​ ​case​ .​Earth​:
​ ​println​(​"Mostly harmless"​)
​ ​default​:
​ ​println​(​"Not a safe place for humans"​)
​ }
​} ​else​ {
​ ​println​(​"There isn't a planet at position ​\(​positionToFind​)​"​)
​}
​// prints "There isn't a planet at position 9"

上面例子使用了可选绑定,试图根据原始值9访问一个行星。语句 if let somplanet=Planet(rawValue:9)创建了一个可选Planet,如果 可选Planet的值可以检索,将会把这个值赋值给somPlanet。这个例子中,根据9得不到可检索的值,所以else分支将会执行。

[翻译]Swift编程语言——枚举的更多相关文章

  1. ios – 无法识别的选择器发送到实例NSTimer Swift

    解决方法让updateTime成为一个类方法.如果它是在一个纯粹的Swift类中,你需要在@objc前面说明该方法的声明,如:

  2. iOS >>块>>更改块外部的变量值

    我不是在处理一个Object并改变它,就像我的mString一样.我希望’center’属性的行为类似于myInt,因为它是直接访问的C结构,而不是指向对象的指针.我希望’backgroundColor’的行为类似于我的imstring,因为它是一个指向一个新对象的对象的指针,不是吗?

  3. ios – 类型推断(自动类型检测)如何在swift中工作?

    LLVM如何检测变量是一个字符串?

  4. ios – Swift可选项:语言问题,还是做错了什么?

    应该有可选的类型;type是但是,如果我这样做,它的工作原理:它似乎是基本的替代,但我可能会遗漏一些语言的细微差别.谁能对此有所了解?之后就像暧昧一样,更多,这是我的解决方案:这适用于所有非对象Swift对象,包括Swift字符串,数字等.感谢Viktor提醒我String不是Swift中的对象.如果您知道值的类型,您可以替换任何?使用适当的可选类型,如String?

  5. ios – 覆盖Swift中的超类委托

    我正在开发一个包含两个UIViews的Swift(v1.2)项目.MyView和MyViewSubclass.MyView有一个委托,我想在MyViewSubclass中覆盖它作为一个子协议,类似于UITableViews有一个UITableViewDelegate,它也符合超级uiscrollviewdelegate.我的第一个想法是覆盖超类属性,但这会导致编译器错误,因为子类不能覆盖具有不同类

  6. ios – 我可以在swift中将字符串转换为代码块吗?

    有没有办法将字符串转换为代码块?

  7. ios – Swift:方法重载只在返回类型上有所不同

    我一直在看Swift类,其中定义了两种方法,它们的返回类型不同.我不习惯使用允许这种语言的语言,所以我去寻找描述它如何在Swift中工作的文档.我在任何地方都找不到任何东西.我本来期望在Swift书中有关于它的整个部分.这记录在哪里?

  8. ios – 字符串资源Xcode swift

    我是iOS开发和Swift语言的新功能.而且我尝试制作简单的iOS应用程序,我需要在应用程序中使用一些字符串资源.当然,我可以将这个字符串放在我的*.swift文件中作为常量,但我认为这是一个坏的方法.我该怎么做?

  9. IOS键盘默认按钮翻译

    实际上,我只需要在十进制键盘上将“done”/“pref”/“next”按钮翻译成俄语或其他语言.顺便说一下,本地化的应用程序在俄语中.此外,当我改变本地化语言时,所有其他按钮,如“取消”在其他控件被自动翻译.但不是这样.可以不经过定制吗?

  10. ios – 如何使用新的Apple Swift语言发布JSON

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部