Swift-枚举

133 阅读5分钟

1.枚举定义

1.1普通枚举

//1.枚举-首都
enum CapitalOfChina{
   case Beijing
}

//2枚举-方向
enum Direction{
    case north
    case south
    case west
    case east
}
//等价于
enum Direction {
    case north,south,west,east
}

此时枚举成员中存储的是成员下标值,从0开始。

1.2原始值&隐式原始值枚举

原始值:Raw Value
隐式原始值:Implicitly Assigned Raw Values
在定义枚举时,可以为枚举中的成员变量定义默认值,也就是原始值;给成员变量定义原始值时,必须先定义枚举类型,不然编译不通过。

//定义原始值枚举的形式
enum name : type {
 case T = value
}
enum Number : Int{
    case one = 1
    case two = 2
    case three = 3
    case four = 4
}

//获取枚举成员的原始值
let number = Number.four
print(number.rawValue)//打印结果:4

//Int型枚举,给其中一个成员赋原始值后,默认其后面的原始值为其原始值递增值。
enum Number1 : Int{
    case one = 1  //rawValue = 1
    case two      //rawValue = 2
    case three = 4//rawValue = 4
    case four     //rawValue = 5
}
//String类型的枚举,不定义原始值时,会默认原始值为其成员名本身
enum Direction:String{
    case north //rawValue = north
    case south //rawValue = south
    case west  //rawValue = west
    case east  //rawValue = east
}
//Int类型的枚举不定义原始值时,原始值默认从0开始。
enum Number2 : Int{
    case one   //rawValue = 0
    case two   //rawValue = 1
    case three //rawValue = 2
    case four  //rawValue = 3
}

Tips:
1)枚举类型为Int、String类型,Swift会自动分配原始值:

  • Int类型时原始值从0开始递增+1;
  • String类型原始值为枚举成员名;
    2)定义了枚举类型的枚举才可以使用.rawValue获取枚举成员的原始值。

1.3关联值枚举

枚举中的成员可以如同函数一样定义入参;比如:使用Moya封装APP网络请求,根据每个接口定义不同的枚举成员;

enum SWNetworkAPI{
    case signIn(userName:String,passWord:String,token:String)//登录
    case getUserInformation(userId:String)//获取用户信息
    case getAppVersion//获取APP版本
}
//使用方法
let request = SWNetworkAPI.getAppVersion
switch request {
  case .signIn(let userName,let passWord,let token):
            //code
  case let .getUserInformation(userId):
            //code
  case .getAppVersion:
            //code
  default:
           //other code
}

在Switch-case中使用关联值枚举时,带有参数的枚举成员有三种实现形式:

  • case let .getUserInformation(userId):此时成员变量中的入参数都是常量;同理,如果用var就是变量;
  • case .signIn(let userName,let passWord,let token):在每个参数前添加let修饰;
  • case .signIn(userName,passWord,token):参数默认为常量。

据说:let必要时可以更换为var,实现没有成功;如果以后实现了后续会添加进来。

1.4递归枚举

递归枚举:Recursive Enumeraton 递归枚举就是枚举成员使用了枚举本身作为关联值,可以在枚举中调用自己,达到一种链式表达式,使用indirect关键字修饰;
举个🌰:定义一个计算器,计算(5+4)*3

indirect enum Caculator{
    case number(Int) 
    case sum(Caculator,Caculator)
    case multiple(Caculator,Caculator)
}

//等价于
enum Caculator{
    case number(Int) 
    indirect case sum(Caculator,Caculator)
    indirect case multiple(Caculator,Caculator)
}

//定义个计算函数
func calculate(_ expr : Caculator) -> Int{
     switch expr {
        case .number(let value):
            return value
        case .sum(let number1, let number2):
            return calculate(number1) + calculate(number2)
        case .multiple(let number1, let number2):
            return calculate(number1) * calculate(number2)
    }
}

let five = Caculator.number(5)
let four = Caculator.number(4)
let sum = Caculator.sum(five, four)
let three = Caculator.number(3)
let mutiple = Caculator.multiple(sum, three)
print(mutiple)//打印结果:27

2.枚举内存&枚举变量内存

前两篇学习了如何获取内存大小、内存地址、如何看内存分布;以此对枚举内存进行了分析,得出如下结论

  • 枚举内存中有一个字节存储成员值;
  • N个字节存储关联值(N取占用内存最大的关联值),任何一个成员的关联值都共用这个N个字节;
  • 普通型、原始值类型、隐式原始值类型枚举:内存只占一个字节,只存储了成员值;
  • 原始值类型、隐式原始值类型的枚举,原始值不存储枚举内存中; 枚举内存对齐原则:
  • 关联值类型枚举对齐系数为8,也就是说内存大小必须是8的倍数;
  • 关联值类型枚举内存去关联值内存最大;
  • 原始值类型枚举对齐系数为1;
enum AssociatedEnum{
    case add(Int,Int,Bool)//Int:8个字节;Bool:1个字节;总共17个字节。
    case test3(Int)
    case test4(Bool)
    case test5
}
print(MemoryLayout<AssociatedEnum>.size)//打印结果:17
print(MemoryLayout<AssociatedEnum>.stride)//打印结果:24
print(MemoryLayout<AssociatedEnum>.alignment)//打印结果:8

最后一个为对齐系数,所以对齐系数为8.

3.枚举的扩展

在枚举中:

  1. 只可以创建计算属性且必须实现;因为枚举关联值存储在枚举中,如果声明存储属性会与关联值产生歧义。
  2. 可以声明方法且必须实现
    枚举可以进行扩展,枚举扩展中:
  3. 只可以创建计算属性且必须实现
  4. 可以声明方法且必须实现

计算属性与存储属性的区别:

区别在于是否直接存储值;

  • 计算属性:需要通过提供一个getter方法来获取值,也可以通过setter方法来设置属性值变化。
  • 存储属性:用于存储一个常量或变量。

举个🌰::主要根据不同状态,显示不同字体颜色。

enum UploadStatus : String {
    case Uploading = "正在上传"
    case Waiting = "等待上传"    
    case Success = "完成"
    case Error = "失败"
    case Cancel = "取消"
}

//枚举扩展,添加变量
extension UploadStatus { // 状态对应颜色
    var textColor : UIColor {
        switch self {
        case .Error :
            return UIColor.red
        case .Cancel :
            return UIColor.lightGray
        default:
            return UIColor(red: 11/255.0, green: 96/255.0, blue: 254/255.0, alpha: 1)
        }
    }
}

//枚举变量声明与调用
let status = UploadStatus.Uploading
self.label.textColor = status.textColor

4.关联值和原始值的区别

  • 关联值直接存储在枚举的内存中;枚举成员值时可以改变的,所以需要按照关联值类型分配内存;
  • 原始值和枚举成员绑定,枚举成员值是不可改变的;此时枚举成员占用1个字节;

5.推荐文章:

全是干货,先Mark这里;
www.jianshu.com/p/d25860cf8…