Swift中枚举的使用方法简单介绍

枚举我们大家都不太陌生了,我们在C或者OC中经常使用到,在这里简单记录下Swift中枚举的使用方法.

枚举的定义

“在 Swift 中,枚举类型是一等(first-class)类型。它们采用了很多在传统上只被类(class)所支持的特性,例如计算型属性(computed properties),用于提供枚举值的附加信息,实例方法(instance methods),用于提供和枚举值相关联的功能。枚举也可以定义构造函数(initializers)来提供一个初始值;可以在原始实现的基础上扩展它们的功能;还可以遵守协议(protocols)来提供标准的功能。”

枚举的语法

使用enum关键词来创建枚举并且把它们的整个定义放在一对大括号内:
下面是用枚举表示指南针四个方向的例子:

enum CompassPoint {
    case North
    case South
    case East
    case West
}

枚举中定义的值(如 North,South,East和West)是这个枚举的成员值(或成员)。使用case关键字来定义一个新的枚举成员值。

注意:

与 C 和 Objective-C 不同,Swift 的枚举成员在被创建时不会被赋予一个默认的整型值。在上面的CompassPoint例子中,North,South,East和West不会被隐式地赋值为0,1,2和3。相反,这些枚举成员本身就是完备的值,这些值的类型是已经明确定义好的CompassPoint类型。多个成员值可以出现在同一行上,用逗号隔开:

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

每个枚举定义了一个全新的类型。像 Swift 中其他类型一样,它们的名字(例如CompassPoint和Planet)必须以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于读起来更加容易理解:
可以使用switch语句匹配单个枚举值:

directionToHead = .South
switch directionToHead {
    case .North:
 print("Lots of planets have a north")
    case .South:
        print("Watch out for penguins")
“case .East:
        print("Where the sun rises")
    case .West:
        print("Where the skies are blue")
}
// 输出 "Watch out for penguins”

关联值(Associated Values)

在 Swift 中,我们还可以定义这样的枚举类型,它的每一个枚举项都有一个附加信息,来扩充这个枚举项的信息表示,这又叫做关联值。加入我们有一个枚举类型Shape
来表示形状。这个形状可以是矩形,也可以是圆形,等等。而每种具体的形状又对应了不同的属性,比如矩形有长,宽,圆形有,圆心,半径,等等。那么枚举的关联值就可以帮我们解决这个问题:

enum Shape { case Rectangle(CGRect) case Circle(CGPoint,Int)}

我们看到,每个枚举项的后面,都包含了一对括号,这里面定义了这个枚举项的关联值的类型。对于Rectangle我们使用一个CGRect来表示他的原点和长宽属性。而对于Circle
,我们使用一个包含了CGPointInt类型的元组(Tuple) 来表示这个圆的圆心和半径。
这样我们在初始化枚举类型的时候,我们就可以根据每个枚举项的关联值类型,为它指定附加信息了:

var rect = Shape.Rectangle(CGRectMake(0, 0, 200, 200))var circle = Shape.Circle(CGPointMake(25, 25), 20)

原始值(Raw Values)

“原始值和关联值是不同的。原始值是在定义枚举时被预先填充的值。对于一个特定的枚举成员,它的原始值始终不变。关联值是创建一个基于枚举成员的常量或变量时才设置的值,枚举成员的关联值可以变化。

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

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

例如,当使用整数作为原始值时,隐式赋值的值依次递增1。如果第一个枚举成员没有设置原始值,其原始值将为0。
下面的枚举是对之前Planet这个枚举的一个细化,利用整型的原始值来表示每个行星在太阳系中的顺序:

enum Planet: Int {
    case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}```
在上面的例子中,Plant.Mercury的显式原始值为1,Planet.Venus的隐式原始值为2,依次类推。
当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称。
下面的例子是CompassPoint枚举的细化,使用字符串类型的原始值来表示各个方向的名称:

enum CompassPoint: String {
case North, South, East, West
}

上面例子中,CompassPoint.South拥有隐式原始值South,依次类推。

使用枚举成员的rawValue属性可以访问该枚举成员的原始值:

let earthsOrder = Planet.Earth.rawValue
// earthsOrder 值为 3

let sunsetDirection = CompassPoint.West.rawValue
// sunsetDirection 值为 "West”

######使用原始值初始化枚举实例(Initializing from a Raw Value)

如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法接收一个叫做rawValue的参数,参数类型即为原始值类型,返回值则是枚举成员或nil。你可以使用这个初始化方法来创建一个新的枚举实例
#####递归枚举(Recursive Enumerations)
递归枚举(recursive enumeration)是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上indirect来表示该成员可递归。

这些只是对枚举的大体介绍,具体的解释请查阅文档.
####项目实例
做好了铺垫,接下来就说一下枚举在项目中的使用,我在大牛的代码里面看见一个功能,截图如下:
![屏幕快照 2016-03-14 22.31.08.png](http://upload-images.jianshu.io/upload_images/668737-9964686e49d1fb43.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
如果按我思路的话就是利用tableView,结果我看大牛是用了枚举来做的,感觉特别有意思,所以在此作为记录.
言归正传,上代码:

1 首先定义支付类型的枚举:

声明支付方式的枚举类型,这里我们可以看到给每个枚举赋了原始值,它的作用在下面将会体现出来
enum PayMethodsType: Int {
case WeChat = 0
case QQ = 1
case AliPay = 2
case Delivery = 3
}

2 自定义一个View用来表示每种支付方式的小组件:
![屏幕快照 2016-03-14 23.35.52.png](http://upload-images.jianshu.io/upload_images/668737-88c6ab46c5a0b151.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

//MARK:-支付类型View
class PayMethodsView: UIView {

//支付类型
private var payType: PayMethodsType?
//支付类型的图标
private let payIconImageView = UIImageView(frame: CGRectMake(20, 10, 20, 20))
//支付类型的名称
private let payTitleLabel:UILabel = UILabel(frame: CGRectMake(55,0, 150, 40))
//被选中的支付类型回调
private var selectedCallBlock:((type: PayMethodsType) -> Void)?
//每种支付类型中的选择按钮
let selectedBtn: UIButton = UIButton(frame: CGRectMake(ScreenWidth - 10 - 16, (40 - 16) * 0.5, 16, 16))

//MARK:-重写init方法 在init中初始化每个控件
override init(frame: CGRect) {
    super.init(frame: frame)
    
    payIconImageView.contentMode = UIViewContentMode.ScaleAspectFill
    addSubview(payIconImageView)
    
    payTitleLabel.textColor = UIColor.blackColor()
    payTitleLabel.font = UIFont.systemFontOfSize(14)
    addSubview(payTitleLabel)
    
    selectedBtn.setImage(UIImage(named: "v2_noselected"), forState: .Normal)
    selectedBtn.setImage(UIImage(named: "v2_selected"), forState: .Selected)
    selectedBtn.userInteractionEnabled = false
    addSubview(selectedBtn)
    
    lineView(CGRectMake(15, 0, ScreenWidth - 15, 0.5))
    
    //手势
    let tap = UITapGestureRecognizer(target: self, action: "selectedPayView")
    addGestureRecognizer(tap)
    
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

//线
private func lineView(frame:CGRect) {
    let lineView: UIView = UIView(frame: frame)
    lineView.backgroundColor = UIColor.blackColor()
    lineView.alpha = 0.1
    addSubview(lineView)
}

//便利构造法
convenience init(frame: CGRect, payType:PayMethodsType, selectedCallBlock: ((type:PayMethodsType) -> ())) {
    self.init(frame:frame)
    self.payType = payType
    
    //根据枚举进行判断
    switch payType {
    case .WeChat:
        payIconImageView.image = UIImage(named: "v2_weixin")
        payTitleLabel.text = "微信支付"
        break
    case .QQ:
        payIconImageView.image = UIImage(named: "icon_qq")
        payTitleLabel.text = "QQ钱包"
        break
    case .AliPay:
        payIconImageView.image = UIImage(named: "zhifubaoA")
        payTitleLabel.text = "支付宝支付"
        break
    case .Delivery:
        payIconImageView.image = UIImage(named: "v2_dao")
        payTitleLabel.text = "货到付款"
        break
    }
    self.selectedCallBlock = selectedCallBlock
}
//MARK:Tap Action
func selectedPayView() {
    selectedBtn.selected = true
    if selectedCallBlock != nil && payType != nil {
        selectedCallBlock!(type: payType!)
    }
}

}

我们可以看见在```PayMethodsView```这个类中,将view中的元素声明出来,在这里我们声明了一个回调函数,表示被选中的支付类型回调方法,在init方法中 给view添加手势,这个手势方法中

func selectedPayView() {
selectedBtn.selected = true
if selectedCallBlock != nil && payType != nil {
selectedCallBlock!(type: payType!)
}
}

用来传递点击回调的闭包.将枚举类型Type作为参数传递.

在这个```PayMethodsView```类中用到了便利构造法,在另一个类中创建继承自```PayMethodsView```子类的时候用便利构造法给所需要创建的view初始化出一个专属的样式.在```convenience init```中,根据枚举进行判断给view中的空间自定义image和text.

3 支付方式主题界面:

//MARK:-支付界面View
class PayView: UIView {
private var weChatView: PayMethodsView?
private var qqPurseView:PayMethodsView?
private var alipayView: PayMethodsView?
private var deliveryView:PayMethodsView?

override init(frame: CGRect) {
    super.init(frame: frame)
    
    //注意:用weak修饰self 避免在闭包中的循环引用
    weak var tmpSelf = self
    
    //在支付界面初始化每一项具体的类型的支付方式view的时候 用上面先写好的便利构造法的初始化方式,这里便利构造法中我们已经为此界面量身定做了一套专属的view排版
    weChatView = PayMethodsView(frame: CGRectMake(0, 0, ScreenWidth, 40), payType: .WeChat, selectedCallBlock: { (type) -> () in
        tmpSelf?.setSelectedPayView(type)
        print("微信支付")
    })
    weChatView?.selectedBtn.selected = true
    qqPurseView = PayMethodsView(frame: CGRectMake(0, 40, ScreenWidth, 40), payType: .QQ, selectedCallBlock: { (type) -> () in
        tmpSelf?.setSelectedPayView(type)
        print("QQ钱包")
    })
    alipayView = PayMethodsView(frame: CGRectMake(0, 80, ScreenWidth, 40), payType: .AliPay, selectedCallBlock: { (type) -> () in
        tmpSelf?.setSelectedPayView(type)
        print("支付宝支付")
    })
    deliveryView = PayMethodsView(frame: CGRectMake(0, 120, ScreenWidth, 40), payType: .Delivery, selectedCallBlock: { (type) -> () in
        tmpSelf?.setSelectedPayView(type)
        print("货到付款")
    })
    
    addSubview(weChatView!)
    addSubview(qqPurseView!)
    addSubview(alipayView!)
    addSubview(deliveryView!)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


//MARK:-根据枚举类型的原始值对支付类型的view进行选择操作
func setSelectedPayView(type: PayMethodsType) {
    
    weChatView?.selectedBtn.selected = type.rawValue == PayMethodsType.WeChat.rawValue
    qqPurseView?.selectedBtn.selected = type.rawValue == PayMethodsType.QQ.rawValue
    alipayView?.selectedBtn.selected = type.rawValue == PayMethodsType.AliPay.rawValue
    deliveryView?.selectedBtn.selected = type.rawValue == PayMethodsType.Delivery.rawValue
}

}

private var weChatView: PayMethodsView?
private var qqPurseView:PayMethodsView?
private var alipayView: PayMethodsView?
private var deliveryView:PayMethodsView?

每个view都继承自我们刚刚创建的```PayMethodsView```类
利用```convenience init```进行对象的初始化,我们每点击一次支付方式的选项都会执行```tap```的```selectedPayView```方法,将Type通过闭包传到

func setSelectedPayView(type: PayMethodsType) {

    weChatView?.selectedBtn.selected = type.rawValue == PayMethodsType.WeChat.rawValue
    qqPurseView?.selectedBtn.selected = type.rawValue == PayMethodsType.QQ.rawValue
    alipayView?.selectedBtn.selected = type.rawValue == PayMethodsType.AliPay.rawValue
    deliveryView?.selectedBtn.selected = type.rawValue == PayMethodsType.Delivery.rawValue
}
这个函数中,然后通过枚举的原始值进行```selectedBtn.selected```的判断,在这个函数中,从上到下都会执行一遍,直到找到枚举原始值相等的时候才会给```selectedBtn```做出判断.

4 在控制器中:

//MARK:- 创建支付界面
private func buildPayView() {

    let payBaseView = UIView(frame: CGRectMake(0, 100, ScreenWidth, 190))
    payBaseView.backgroundColor = UIColor.whiteColor()
    view.addSubview(payBaseView)
    
    buildLabel(CGRectMake(15, 0, 150, 30), textColor: UIColor.lightGrayColor(), font: 12, addView: payBaseView, text: "选择支付方式")
    
    let payView: PayView = PayView(frame: CGRectMake(0, 30, ScreenWidth, 160))
    payBaseView.addSubview(payView)
    
    let lineView = createLineView(CGRectMake(0, 189, ScreenWidth, 1))
    payBaseView.addSubview(lineView)
    
}
参考了:维尼的小熊 《iOS高仿爱鲜蜂 》http://www.jianshu.com/p/879f58fe3542

swiftCafe 《Swift 中的枚举,你应该了解的东西》
http://www.jianshu.com/p/288873e6f5a4

 极客学院. “The Swift Programming Language 中文版”。 iBooks. 

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

推荐阅读更多精彩内容