原文出自:标哥的技术博客

前言

枚举为一组相关的值定义了一个共同的类型,使你可以在你的代码中以类型安全的方式来使用这些值,当然还有一个很重要的是它可能智能提示。

在C语言中,枚举会为一组整型值分配相关联的名称。Swift中的枚举更加灵活,不必给每一个枚举成员提供一个值。如果给枚举成员提供一个值(原始值),则该值的类型可以是字符串、字符、整型值或浮点数。

此外,枚举成员可以指定任意类型的关联值存储到枚举成员中,每一个枚举成员都可以有适当类型的关联值。

在Swift中,枚举类型是一等(first-class)类型,拥有在传统上只被类(class)所支持的特性,例如计算型属性用于提供枚举值的附加信息、实例方法用于提供和枚举值相关联的功能等、定义构造函数来提供一个初始值、可在原始实现的基础上扩展功能、可遵守协议来提供标准的功能等。

枚举语法(Enumeration Syntax)

使用enum关键词来创建枚举并且把它们的整个定义放在一对大括号内:

enum SomeEnumeration {
    // 枚举定义放在这里
}

例如,我们声明一个上、下、左、右方向的枚举:

enum Directionoperation {
  case Up
  case Down
  case Left
  case Right
}

// 指定方向为上
var direction = Directionoperation.Up

那么dir的数据类型是什么呢?它是Directionoperation类型,因为swift中的枚举不会自动给成员赋值为0,1…,它们本身就已经有完整的类型,那就是Directionoperation。当然我们也可以指定类型。

direction已经被赋值过,其数据类型已经明确,当我们再修改值时,不用在前面指定类型,而是只用枚举值就可以了:

direction = .Down

多个成员值可以出现在同一行上,用逗号隔开:

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

Switch匹配枚举值

enum Direction  {
  case north
  case South
  case East
  case West
}

let direction = Direction.south
switch direction {
case .north:
  print("north")
case .South:
  print(direction)
case .East:
  print("east")
case .West:
  print("west")
}

当不需要匹配每个枚举成员的时候,你可以提供一个default分支来涵盖所有未明确处理的枚举成员:

let somePlanet = Planet.Earth
switch somePlanet {
case .Earth:
    print("Mostly harmless")
default:
    print("Not a safe place for humans")
}
// 输出 "Mostly harmless”

关联值(Associated Values)

swift中的枚举与objective-c中的枚举有很大的区别,swift中的枚举可以做到很多的功能,相当于是强化版本。

对于关联值,其实就是将某个成员的值要求是某种类型值,它们可以是不同类型的组合,这看起来有点像元组,因为元组也是不要求类型相同的。

我们假设这么一个场景:cell上有两个view,可以同时展开、同时收起、可以一个展开一个收起,那么我们就可以通过枚举类型来完成这样一个标识。

我们可以这么声明(不要在乎这里的命名,只是为了写个例子):

enum ExpandStatus {
  case View1Status(Bool)
  case View2Status(Bool)
}

那么如何使用呢?可以这样:

let status = ExpandStatus.View1Status(true)
switch status {
case .View1Status(let isExpand):
  if isExpand {
    // view1展开
  } else {
    // view1收起
  }
case .View2Status(let isExpand):
  if isExpand {
    // view2展开
  } else {
    // view2收起
  }
}

使用枚举的目的是什么?为什么不直接使用常量?为什么不使用其它方式?当然,使用枚举自然有它的好处,不然谁会用呢?有什么好处?在笔者看来,它有以下好处:

  • 枚举类型可以很明确语义,通过看枚举定义就可以看出来这个枚举代表什么,它又有几中状态,都可以直接看到。也就是说,如果有逻辑在内,那么通过枚举有多少个case,基本就是有多少种状态。
  • 枚举类型易扩展。想想这么一种场景:突然有一天产品经理说,这里再增加一种状态,那么通过枚举就很容易实现,直接添加一个case分支即可,然后在相应要处理代码逻辑的地方,添加上新的分支处理逻辑就OK了。
  • 枚举有关联值,它可以像函数那样简单调用。有时候一种状态是由多个值组合而成时,使用枚举的关联值就可以实现,而且语义依然很明确。如果是使用函数调用,那么就优化而言,自然没有枚举那么好。另外,关联值可以直接使用,它相当于传参数,而且还是明确的类型的参数。
  • 使用枚举易维护。为什么说易维护,大家看到枚举大概就知道这是干嘛用的,有几种情况了吧。比那些直接使用常量或者变量语义要强多了。

笔者所能想到的好处,暂时就想到这么多了。大家认为还有哪些好处,可以在评论中回复哦!笔者会整理到文章中的。

原始值的隐式赋值(Implicitly Assigned Raw Values)

在使用原始值为整数或者字符串类型的枚举时,不需要显式地为每一个枚举成员设置原始值,Swift 将会自动为你赋值。

原始值类型为整型

我们利用整型的原始值来表示每个行星在太阳系中的顺序:

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

因为我们明确指定的Planet类型的原始值类型为Int,那么它的成员的原始值都会是Int类型,如果我们不指定,那么它的成员会被自动赋值。

// 1
let mercury = Planet.Mercury.rawValue

// 2
let Venus = Planet.Venus.rawValue

那么后面的几个的原始值依次为3,4,5…

原始值类型为字符串

下面我们声明一个指定原始值类型为String,注意Compasspoint类型是枚举类型,而不是String类型,大家不要搞混了:

enum Compasspoint: String {
    case north,South,East,West
}
``

那么对应的原始值为:

// north
let north = Compasspoint.north.rawValue

// South
let south = Compasspoint.south.rawValue

#原始值初始化实例(Initializing from a Raw Value)

如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做rawValue的参数,参数类型即为原始值类型,返回值则是枚举成员或nil。你可以使用这个初始化方法来创建一个新的枚举实例。

// p 就是Compasspoint.north
let p = Compasspoint(rawValue: “north”)

#递归枚举(Recursive Enumerations)

使用`indirect`关键字指定该分支可以递归,注意像下面所定义的Add表达式中的递归参数类型那就是枚举类型才能递归哦:

enum Expression {
case Number(Int)
indirect case Add(Expression,Expression)
indirect case multiple(Expression,Expression)

func getResultValue() ->Int {
switch self {
case .Number(let value):
return value
case .Add(let lhs,let rhs):
return lhs.getResultValue() + rhs.getResultValue()
case .multiple(let lhs,let rhs):
return lhs.getResultValue() * rhs.getResultValue()
}
}
}

我们来使用一下,看看这递归枚举如何使用:

// 3
let one = Expression.Number(1)
let two = Expression.Number(2)
let addResult = Expression.Add(one,two)

// 1
print(one.getResultValue())
// 2
print(two.getResultValue())
// 3
print(addResult.getResultValue())
“`

swift给我们提供了这样的功能,有什么用呢?直接使用函数不就完事了吗?干嘛非得还要再用递归枚举呢?

我认为这苹果如此设计自有其道理,笔者觉得它的妙用之处在于简单递归、语义明确。如果是复杂的递归,因为类型不同,使用枚举递归就不太合适了。

关注我

如果在使用过程中遇到问题,或者想要与我交流,可加入有问必答QQ群:324400294

关注微信公众号:iOSDevShares

关注新浪微博账号:标哥Jacky

标哥的GITHUB地址:CoderJackyHuang

支持并捐助

如果您觉得文章对您很有帮忙,希望得到您的支持。您的捐肋将会给予我最大的鼓励,感谢您的支持!

支付宝捐助 微信捐助

swift枚举的更多相关文章

  1. 泛型 – Xcode构建错误时,我添加枚举到泛型类?

    为什么在将泛型类添加到枚举时会收到错误:错误:但是当我这样做时,我没有收到错误:或这个:解决方法您不能将任何类型嵌套在通用的类型中,反之亦然.换句话说,你不能像类,结构和枚举这样做的事情:和乃至苹果人explained的限制原因:It’sanimplementationlimitation.We’llremovetherestrictiononceourcompilerandruntimearea

  2. ios – 嵌套递归函数

    我试图做一个嵌套递归函数,但是当我编译时,编译器崩溃.这是我的代码:编译器记录arehere解决方法有趣的…它似乎也许在尝试在定义之前捕获到内部的引用时,它是bailing?以下修复它为我们:当然没有嵌套,我们根本没有任何问题,例如以下工作完全如预期:我会说:报告!

  3. 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 10 Enumerations

    Swift中的枚举更加灵活,不必给每一个枚举成员提供一个值。如果一个值被提供给每个枚举成员,则该值可以是一个字符串,一个字符,或是一个整型值或浮点值//2.EnumerationSyntax//_______________________________________________________________________________________________//使用enum关键字创建枚举enumCompasspoint{//枚举名一般大写,与C不同,Swift中枚举不会默认元素赋值

  4. Swift语法基础:5 - Swift的枚举和结构体

    在Siwft中的枚举类型以及结构体,是和OC中差不多的,但Swift中又有一些特性,下面让我们来看看:1.枚举的声明及使用PS:这里解释一下,枚举类型第一个开始的参数都是1,无论你是有多少case,都会递增的,比如例子的的Ace是1,那么Two就是名副其实的2,Three就是3,以此类推,一直到King,就是13,而enum里面有一个方法,这里面这个方法只是说可以在enum里定义方法,但我这个例子

  5. Swift面向对象的类型

    1、类2、结构体3、枚举在swift语言中通过类和结构体实现面向对象,在Swift语言中,枚举也具有面向对象的特性示例和对象在面向对象中,将类创建对象的过程称为实例化,因此将对象称为实例化,但是在swift中,枚举和结构体不能称为对象,因为结构体和枚举并不是彻底的面向对象类型,而是只包含了一些面向对象的特定,例如,在Swift中继承只发生在类上,结构体和枚举不能继承

  6. Swift基础语法: 24 - Swift的枚举语法, 匹配枚举值和 Switch 语句, 关联值, 原始值

    在前面,我们把函数和闭包解决完毕了,现在让我们来看看Swift中的枚举和Switch:1.枚举语法所谓的枚举其实就是定义一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值。

  7. swift与枚举

    每个原始值在它的枚举声明中必须是唯一的。andequalsPlanet.Uranus//GCD演示//高效循环实现原理:将循环的每次迭代提交到dispatchqueue进行处理,结合并发queue使用时,可以并发地执行迭代以提高性能。但是也不是任何一个循环都需要用dispatch_apply来替换,因为dispatchqueue还是存在一些开销的,虽然非常小。所以只有当你的循环代码拥有足够的工作量,才能忽略掉dispatchqueue的这些开销以提高性能。

  8. Swift 2

    letlabel="Thewidthis"letwidth=94letwidthLabel=label+String练习:删除最后一行中的String,错误提示是什么?你可以一起使用if和let来处理值缺失的情况。switch支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。运行switch中匹配到的子句之后,程序会退出switch语句,并不会继续向下运行,所以不需要在每个子句结尾写break。

  9. swift之方法

    结构体和枚举能够定义方法是Swift与C/Objective-C的主要区别之一。Swift中的方法和Objective-C中的方法极其相似。和函数参数不同,对于方法的参数,Swift使用不同的默认处理方式,这可以让方法命名规范更容易写。具体来说,Swift默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称局部参数名称和外部参数名称。

  10. swift语言学习-10.枚举

    里面的成员用case申明,有点像switch。像Swift中其他类型一样,它们的名字必须以一个大写字母开头。每个原始值在它的枚举声明中必须是唯一的。当整型值被用于原始值,如果其他枚举成员没有值时,它们会自动递增。我们用上面的switch来匹配下是不是等于UranusletpositionToFind9ifsomePlanet"Mostlyharmless"}}else"Thereisn'taplanetatposition\"//输出"Thereisn'taplanetatposition9这个范例使用可

随机推荐

  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,所以编译器会报错,现在来一一解决。

返回
顶部