swift基础-枚举语法

1
2
3
4
5
6
7
8
9
10
enum CompassPoint {
case North
case South
case East
case West
}

enum Planet {
case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
  • North,South,East和West不会被隐式地赋值为0,1,2和3。相反,这些枚举成员本身就是完备的值,这些值的类型是已经明确定义好的CompassPoint类型。多个成员值可以出现在同一行上,用逗号隔开:

关联值(Associated Values)

  • 对于Rectangle我们使用一个CGRect来表示他的原点和长宽属性。而对于Circle我们使用一个包含了CGPoint和Int类型的元组(Tuple) 来表示这个圆的圆心和半径。
  • 关联值是创建一个基于枚举成员的常量或变量时才设置的值,枚举成员的关联值可以变化。
1
2
var rect = Shape.Rectangle(CGRectMake(0, 0, 200, 200))
var circle = Shape.Circle(CGPointMake(25, 25), 20)

原始值(Raw Values)

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

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

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

  • 下面是用枚举表示指南针四个方向的例子:

    1
    2
    3
    4
    5
    6
    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语句匹配单个枚举值:
1
2
3
4
5
6
7
8
9
10
11
12
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
  • ,我们使用一个包含了CGPoint和Int类型的元组(Tuple) 来表示这个圆的圆心和半径。
  • 这样我们在初始化枚举类型的时候,我们就可以根据每个枚举项的关联值类型,为它指定附加信息了:
1
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这个枚举的一个细化,利用整型的原始值来表示每个行星在太阳系中的顺序:
1
2
3
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
  • 在上面的例子中,Plant.Mercury的显式原始值为1,Planet.Venus的隐式原始值为2,依次类推。
  • 当使用字符串作为枚举类型的原始值时,每个枚举成员的隐式原始值为该枚举成员的名称。
  • 下面的例子是CompassPoint枚举的细化,使用字符串类型的原始值来表示各个方向的名称:
1
2
3
enum CompassPoint: String {
case North, South, East, West
}

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

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

1
2
3
4
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
  • 如果按我思路的话就是利用tableView,结果我看大牛是用了枚举来做的,感觉特别有意思,所以在此作为记录.
  • 言归正传,上代码:

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

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

2 自定义一个View用来表示每种支付方式的小组件:

  • 屏幕快照 2016-03-14 23.35.52.png
    //MARK:-支付类型View
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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!)
}
}
}

我们可以看见在

给view添加手势,这个手势方法中
1
2


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

1
2
3
4
5
6

用来传递点击回调的闭包.将枚举类型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都继承自我们刚刚创建的

1
2
3
4
5
6
7
利用```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
}

这个函数中,然后通过枚举的原始值进行

1
2
3
4



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)

}
`