Swift-枚举、可选项
2021-01-25 本文已影响0人
XTK_iOS
枚举
1. 枚举的基本用法
- 一般用于变量的取值就固定的几种,比如季节:春夏秋冬
enum Direction {
case north
case south
case east
case west
}
enum Direction {
case north, south, east, west
}
var dir = Direction.west
dir = Direction.east
dir = .north
print(dir)//north
switch dir {
case .north:
print("\(dir)")
case .south:
print("\(dir)")
case .east:
print("\(dir)")
case .west:
print("\(dir)")
}
2.关联值
- 将枚举的成员值跟其他类型的关联存储在一起
//成绩可能是具体的值; 也可能是 A B C D来表示
enum Score {
case points(Int)
case grade(Character)
}
var score = Score.points(96)
score = .grade("A")
switch score {
case let .points(i): // let: 是常量还是变量 取决自己
print(i)
case let .grade(i):
print(i)
}
enum Data {
case digit(year: Int, month: Int, day: Int)
case string(String)
}
var data = Data.digit(year: 2021, month: 1, day: 14)
data = .string("2021-01-14")
switch data {
case .digit(let year, let month, let day): // let: 那个是常量那个是变量可以自己进行定义
print("\(year)-\(month)-\(day)")
case let .string(value):
print(value)
}
//手机密码 分为 输入手机密码 和 手势密码
enum Password {
case number (Int, Int, Int, Int)
case gesture (String)
}
var pwd = Password.number(3, 5, 7, 9)
pwd = .gesture("123456")
switch pwd {
case let .number(p1, p2, p3, p4):
print("number is",p1, p2, p3, p4)
case let .gesture(str):
print("gesture is", str)
}
3.原始值
- 枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做:关联值
enum PokerSuit : Character {
case spade = "♠"
case heart = "♥"
case diamond = "♦"
case club = "♣"
}
var suit = PokerSuit.spade
print(suit) //spade
print(suit.rawValue) //♠ 通过 rawValue 属性访问
print(PokerSuit.club.rawValue) //♣
------------------------------------------------
enum Grade : String {
case a = "A"
case b = "B"
case c = "C"
case d = "D"
}
print(Grade.a.rawValue)//A
print(Grade.b.rawValue)//B
print(Grade.c.rawValue)//C
print(Grade.d.rawValue)//D
4.隐形原始值
- 如果枚举的原始值类型是 Int String,swift会自动分配原始值
enum Direction : String { // String 预先关联的原始值 是String类型
case north = "north"
case south = "south"
case east = "east"
case west = "west"
}
||
enum Direction : String {
case north, south, east, west
}
print(Direction.north) //north
print(Direction.south.rawValue) //south
enum Season : Int {
case spring, summer, autumn, winter
}
print(Season.spring.rawValue)//0
print(Season.summer.rawValue)//1
print(Season.autumn.rawValue)//2
print(Season.winter.rawValue)//3
-----------------------------------------------
enum Season : Int {
case spring = 1, summer, autumn = 4, winter
}
print(Season.spring.rawValue)//1
print(Season.summer.rawValue)//2
print(Season.autumn.rawValue)//4
print(Season.winter.rawValue)//5
5.递归枚举
- 自己用到了自己定义的类型,必须加 indirect
indirect enum ArithExpr {
case number(Int)
case sum(ArithExpr, ArithExpr)
case difference(ArithExpr, ArithExpr)
}
------------------------------------------------
enum ArithExpr {
case number(Int)
indirect case sum(ArithExpr, ArithExpr)
indirect case difference(ArithExpr, ArithExpr)
}
let five = ArithExpr.number(5)
let four = ArithExpr.number(4)
let two = ArithExpr.number(2)
let sum = ArithExpr.sum(five, four)
let diff = ArithExpr.difference(sum, two)
//函数 计算
func calculate(_ expr: ArithExpr) -> Int {
switch expr {
case let .number(value):
return value
case let .sum(left, right):
return calculate(left) + calculate(right)
case let .difference(left, right):
return calculate(left) - calculate(right)
}
}
calculate(sum) // 9
6.MemoryLayout
- 使用MemoryLayout获取数据类型占用的内存大小
- 关联值 传进去的值是直接存储到枚举变量内存里
- 原始值 和成员固定绑定一起的,不会存储到枚举变量的内存;
var age = 10
//泛型
MemoryLayout<Int>.size // 8个字节
MemoryLayout<Int>.stride //8
MemoryLayout<Int>.alignment //内存对齐 8
||
MemoryLayout.size(ofValue: age)
MemoryLayout.stride(ofValue: age)
MemoryLayout.alignment(ofValue: age)
//关联值 传进去的值是直接存储到枚举变量内存里
enum Password {
case number(Int, Int, Int, Int)
case other
}
var pwd = Password.number(4, 5, 6, 7) // 32
pwd = .other // 1
MemoryLayout.size(ofValue: pwd) // 33
MemoryLayout<Password>.size // 33 实际用到的空间大小
MemoryLayout<Password>.stride // 40 实际分配占用的空间大小(真正的)
MemoryLayout<Password>.alignment // 8 对齐参数
//----------------------------------------------------
//原始值 和成员固定绑定一起的,不会存储到枚举变量的内存;
enum Season : Int {
case spring = 1, summer = 2, autumn = 3, winter
}
MemoryLayout<Season>.size // 1
MemoryLayout<Season>.stride // 1
MemoryLayout<Season>.alignment // 1
可选项
1.可选项(Optional)
- 可选类型,它允许将值设置为nil
- 在类型名称后面加个问号?来定义一个可选项
var name: String? = "jack"
name = nil
var age: Int? //默认为nil
age = 10
age = nil
var array = [1, 2, 5, 6]
func get(_ index: Int) -> Int? {
if index < 0 || index >= array.count {
return nil
}
return array[index]
}
print(get(1)!) //2
print(get(-1)!) //nil
2.强制解包
- 可选项是对其他类型的一层包装,可以理解为一个盒子
- 如果为nil,那么它是个空盒子
- 如果不为nil,那么盒子里装的是:被包装类型的数据
- 如果要从可选项中取出被包装的数据(将盒子里装的东西取出来),需要使用感叹号!进行强制解包
var age: Int? = 10
var age1: Int = age!
age1 += 10
print(age1)
- 如果对值为nil的可选项(空盒子)进行强制解包,将会产生运行时错误
var age: Int?
age!
3.判断可选项是否包含值
var num = Int("123")
if num != nil {
print("字符串转换整数成功:\(num!)")//123
}else {
print("字符串转换整数失败")
}
4.可选项绑定
- 可以使用可选项绑定来绑定可选项是否包含值
- 如果包含就自动解包,把值给一个临时的常量(let)或者变量(var),并返回ture,否则返回false
if let number = Int("123") {
print("字符串转换整数成功:\(number)")
//number 是强制解包之后的int值
//number 作用域仅限于这个大括号
}else {
print("字符串转换整数失败")
}
enum Season : Int {
case spring = 1, sunmmer, autumn, winter
}
---------------------------------------------------
if let season = Season(rawValue: 1) {
switch season {
case .spring:
print(season)//spring
default:
print(season)
}
} else {
print("no such season")
}
5.等价写法
if let first = Int("4") {
if let second = Int("42") {
if first < second && second < 100 {
print("\(first) < \(second) < 100") // 4 < 42 < 100
}
}
}
||
if let first = Int("4"),
let second = Int("42"),
first < second && second < 100 {
print("\(first) < \(second) < 100") // 4 < 42 < 100
}
6.空合并运算符 ??
- a ?? b
- a 是可选项
- b 是可选项 或者 不是可选项
- b 跟 a 的储存类型必须相同
1 - 如果a 不为nil,就返回a
2 - 如果a 为nil,就返回b
3 - 如果b不是可选项,返回a时会自动解包
let a: Int? = 1
let b: Int? = 2
let c = a ?? b // Optional(1)
---------------------------------------------------
let a: Int? = nil
let b: Int? = 2
let c = a ?? b // Optional(2)
---------------------------------------------------
let a: Int? = nil
let b: Int? = nil
let c = a ?? b // nil
---------------------------------------------------
let a: Int? = 1
let b: Int = 2
let c = a ?? b // 1
---------------------------------------------------
let a: Int? = nil
let b: Int = 2
let c = a ?? b // 2
6.1 多个 ?? 一起使用
let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3 // 1
---------------------------------------------------
let a: Int? = nil
let b: Int? = 2
let c = a ?? b ?? 3 // 2
---------------------------------------------------
let a: Int? = nil
let b: Int? = nil
let c = a ?? b ?? 3 // 3
6.2 ?? 跟if let 配合使用
let a: Int? = nil
let b: Int? = 2
if let c = a ?? b {
print(c) //2
}
//类似 if a!= nil || b != nil
---------------------------------------------------
if let c = a, let d = b {
print(c)
print(d)
}
//类似 if a != nil && b != nil
7.guard 语句
- 当 guard 语句的条件为false时,就会执行大括号里面的代码
- 当 guard 语句的条件为true时,就会跳过guard语句
- guard语句特别适合用来“提前退出”
guard 条件 else {
//do something
退出当前作用域
// return、 break、continue、throw error
}
- 当使用guard 语句进行可选项绑定时,绑定的常量(let)、变量(var)也能在外层作用域中使用
func login(_ info: [String : String]) {
guard let username = info["username"] else {
print("请输入用户名")
return
}
guard let password = info["password"] else {
print("请输入密码")
return
}
print("用户名\(username), 密码\(password)")
}
login(["username" : "jack", "password" : "123456"])
8.隐式解包
- 在某些情况下,可选项一旦被设定值之后,就不会一直拥有值
- 在这种情况下,可以去掉检查,也不必每次访问的时候进行解包,因为它能确定每次访问的时候都有值
- 可以在类型的后面加个感叹号!定义一个隐式解包的可选项
let num1: Int! = 10
let num2: Int = num1
if num1 != nil {
print(num1 + 6)//16
}
if let num3 = num1 {
print(num3)//10
}