swift--枚举

C语言枚举

enum 枚举名 { 
 枚举值1, 
 枚举值2, 
 ……};

一周七天可以写成

enum week 
 { 
   MON, TUE, WED, THU, FRI, SAT, SUN 
 };

第⼀个枚举成员的默认值为整型的 0,后⾯的枚举值依次类推,如果我们想更改,只需要这样操作

enum week 
 { 
   MON = 1, TUE, WED, THU, FRI, SAT, SUN 
 };

那如何定义⼀个枚举变量


enum week 
 { 
   MON = 1, TUE, WED, THU, FRI, SAT, SUN 
 } week;
//可以省略声明的枚举
enum week 
 { 
   MON = 1, TUE, WED, THU, FRI, SAT, SUN 
 } week;

Swift 枚举写法

enum week{
    case MONDAY
    case TUEDAY
    case WEDDAY
    case THUDAY
    case FRIDAY
    case SATDAY
    case SUNDAY
}

上述代码也可以直接⼀个 case ,然后⽤逗号隔开

enum week{
    case MONDAY, TUEDAY, WEDDAY, THUDAY, FRIDAY, SATDAY, SUNDAY
}

枚举值默认是整形,也以表达为String

enum week: String
{
    case MON = "MON"
    case TUE = "TUE"
    case WED = "WED"
    case THU = "THU"
    case FRI = "FRI"
    case SAT = "SAT"
    case SUN = "SUN"
}

我们赋值的字符串叫做原始值(RawValue),,如果我们不想写后⾯的字符串,这个时候我们就 可以使⽤ 隐⼠ RawValue 分配

enum week: Int {  case mon, tue, wed, thu, fri = 10, sat, sun  }
print(week.fri.rawValue)
···········
10


enum week: String {  case MON, TUE, WED, THU, FRI , SAT, SUN  }
print(week.FRI.rawValue)
···········
FRI

当改成String型之后,打印的值就变成了当前枚举值了。
通过swiftc -emit-sil main.swift | xcrun swift-demangle > ./main.sil && open main.sil查看sil代码

enum week : String {
  case MON, TUE, WED, THU, FRI, SAT, SUN
  typealias RawValue = String
  init?(rawValue: String)
  var rawValue: String { get }
}


// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @main.w : Swift.String                     // id: %2
  %3 = global_addr @main.w : Swift.String : $*String      // user: %8
  %4 = metatype $@thin week.Type
  %5 = enum $week, #week.MON!enumelt              // user: %7
  // function_ref week.rawValue.getter
  %6 = function_ref @main.week.rawValue.getter : Swift.String : $@convention(method) (week) -> @owned String // user: %7
  %7 = apply %6(%5) : $@convention(method) (week) -> @owned String // user: %8
  store %7 to %3 : $*String                       // id: %8
  %9 = integer_literal $Builtin.Int32, 0          // user: %10
  %10 = struct $Int32 (%9 : $Builtin.Int32)       // user: %11
  return %10 : $Int32                             // id: %11
} // end sil function 'main'

%6调用了get方法,7%将%5也就是枚举值MON传参进去


// week.rawValue.getter
sil hidden @main.week.rawValue.getter : Swift.String : $@convention(method) (week) -> @owned String {
// %0                                             // users: %2, %1
bb0(%0 : $week):
//声明一个变量self,等于参数week
  debug_value %0 : $week, let, name "self", argno 1 // id: %1
//匹配枚举值,跳转到对应的分支
  switch_enum %0 : $week, case #week.MON!enumelt: bb1, case #week.TUE!enumelt: bb2, case #week.WED!enumelt: bb3, case #week.THU!enumelt: bb4, case #week.FRI!enumelt: bb5, case #week.SAT!enumelt: bb6, case #week.SUN!enumelt: bb7 // id: %2
//创建String,跳转bb8
bb1:                                              // Preds: bb0
  %3 = string_literal utf8 "MON"                  // user: %8
  %4 = integer_literal $Builtin.Word, 3           // user: %8
  %5 = integer_literal $Builtin.Int1, -1          // user: %8
  %6 = metatype $@thin String.Type                // user: %8
  // function_ref String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
  %7 = function_ref @Swift.String.init(_builtinStringLiteral: Builtin.RawPointer, utf8CodeUnitCount: Builtin.Word, isASCII: Builtin.Int1) -> Swift.String : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %8
  %8 = apply %7(%3, %4, %5, %6) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String // user: %9
  br bb8(%8 : $String)                            // id: %9
...
//返回
// %52                                            // user: %53
bb8(%52 : $String):                               // Preds: bb7 bb6 bb5 bb4 bb3 bb2 bb1
  return %52 : $String                            // id: %53
} // end sil function 'main.week.rawValue.getter : Swift.String'

case 和 rawValue

print(week.MON)
print(week.MON.rawValue)

虽然打印的都是MON,但是一个是枚举类型,一个是字符串类型

枚举的init

通过sil文件查看init方法


// week.init(rawValue:)
sil hidden @main.week.init(rawValue: Swift.String) -> main.week? : $@convention(method) (@owned String, @thin week.Type) -> Optional<week> {
// %0                                             // users: %164, %158, %79, %3
bb0(%0 : $String, %1 : $@thin week.Type):
  %2 = alloc_stack $week, var, name "self"        // users: %162, %154, %143, %132, %121, %110, %99, %88, %165, %159
  debug_value %0 : $String, let, name "rawValue", argno 1 // id: %3
  %4 = integer_literal $Builtin.Word, 7           // user: %6
  // function_ref _allocateUninitializedArray<A>(_:)
  %5 = function_ref @Swift._allocateUninitializedArray<A>(Builtin.Word) -> ([A], Builtin.RawPointer) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // user: %6
  %6 = apply %5<StaticString>(%4) : $@convention(thin) <τ_0_0> (Builtin.Word) -> (@owned Array<τ_0_0>, Builtin.RawPointer) // users: %8, %7
//构建元组,存放字符串数组和指针地址
  %7 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 0 // users: %80, %79
  %8 = tuple_extract %6 : $(Array<StaticString>, Builtin.RawPointer), 1 // user: %9
  %9 = pointer_to_address %8 : $Builtin.RawPointer to [strict] $*StaticString // users: %17, %69, %59, %49, %39, %29, %19
  %10 = string_literal utf8 "MON"                 // user: %12
  %11 = integer_literal $Builtin.Word, 3          // user: %16
  %12 = builtin "ptrtoint_Word"(%10 : $Builtin.RawPointer) : $Builtin.Word // user: %16
  br bb1                                          // id: %13

bb1:                                              // Preds: bb0
  %14 = integer_literal $Builtin.Int8, 2          // user: %16
  br bb2                                          // id: %15

bb2:                                              // Preds: bb1
  %16 = struct $StaticString (%12 : $Builtin.Word, %11 : $Builtin.Word, %14 : $Builtin.Int8) // user: %17
  store %16 to %9 : $*StaticString                // id: %17
  %18 = integer_literal $Builtin.Word, 1          // user: %19
  %19 = index_addr %9 : $*StaticString, %18 : $Builtin.Word // user: %27
  %20 = string_literal utf8 "TUE"                 // user: %22
  %21 = integer_literal $Builtin.Word, 3          // user: %26
  %22 = builtin "ptrtoint_Word"(%20 : $Builtin.RawPointer) : $Builtin.Word // user: %26
  br bb3                                          // id: %23


//通过方法来进行匹配
bb14:                                             // Preds: bb13
  %76 = struct $StaticString (%72 : $Builtin.Word, %71 : $Builtin.Word, %74 : $Builtin.Int8) // user: %77
  store %76 to %69 : $*StaticString               // id: %77
  // function_ref _findStringSwitchCase(cases:string:)
  %78 = function_ref @Swift._findStringSwitchCase(cases: [Swift.StaticString], string: Swift.String) -> Swift.Int : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // user: %79
  %79 = apply %78(%7, %0) : $@convention(thin) (@guaranteed Array<StaticString>, @guaranteed String) -> Int // users: %149, %138, %127, %116, %105, %94, %83, %147, %136, %125, %114, %103, %92, %81
  release_value %7 : $Array<StaticString>         // id: %80
  debug_value %79 : $Int, let, name "$match"      // id: %81
  %82 = integer_literal $Builtin.Int64, 0         // user: %84
  %83 = struct_extract %79 : $Int, #Int._value    // user: %84
  %84 = builtin "cmp_eq_Int64"(%82 : $Builtin.Int64, %83 : $Builtin.Int64) : $Builtin.Int1 // user: %85
  cond_br %84, bb15, bb16  


//如果成功,返回
bb15:                                             // Preds: bb14
  %86 = metatype $@thin week.Type
  %87 = enum $week, #week.MON!enumelt             // user: %89
  %88 = begin_access [modify] [static] %2 : $*week // users: %89, %90
  store %87 to %88 : $*week                       // id: %89
  end_access %88 : $*week                         // id: %90
  br bb29                                         // id: %91
//不成功继续匹配
bb16:                                             // Preds: bb14
  debug_value %79 : $Int, let, name "$match"      // id: %92
  %93 = integer_literal $Builtin.Int64, 1         // user: %95
  %94 = struct_extract %79 : $Int, #Int._value    // user: %95
  %95 = builtin "cmp_eq_Int64"(%93 : $Builtin.Int64, %94 : $Builtin.Int64) : $Builtin.Int1 // user: %96
  cond_br %95, bb17, bb18                         // id: %96



bb29:                                             // Preds: bb27 bb25 bb23 bb21 bb19 bb17 bb15
  %162 = load %2 : $*week                         // user: %163
//返回的是可选类型,如果没有就是nil
  %163 = enum $Optional<week>, #Optional.some!enumelt.1, %162 : $week // user: %166
  release_value %0 : $String                      // id: %164
  dealloc_stack %2 : $*week                       // id: %165
  br bb30(%163 : $Optional<week>)  


// %167                                           // user: %168
bb30(%167 : $Optional<week>):                     // Preds: bb29 bb28
  return %167 : $Optional<week>                   // id: %168
} // end sil function 'main.week.init(rawValue: Swift.String) -> main.week?'

枚举的遍历

enum week: String {  case MON, TUE, WED, THU, FRI , SAT, SUN  }

extension week: CaseIterable{}
var allCase = week.allCases
for c in allCase {
    print(c)
}

只要实现了CaseIterable协议就可以。

关联值

如果我们想⽤枚举表达更复杂的信息,⽽不仅仅是⼀个 RawValue 这么简单,这个时候我们就可以使⽤ Associated Value,当声明了关联值后,就无法使用initRawValue

enum Shape{
    case circle(radious: Double)
    case rectangle(width: Int, height: Int)
}

var circle = Shape.circle(radious: 10.0)
circle = Shape.circle(radious: 20.0)
switch circle{
case let .circle(radious):
    print(radious)
case .rectangle(let width, var height):
    height += 10
    print(width,height)
}
//也可以单独取出来用
if case let Shape.circle(radious) = circle{
    print(radious)
}

当我们只关注不同枚举值的相同关联值

enum Shape{
    case rectangle(width: Int, height: Int)
    case squar(width1: Int, height1: Int)
}
var circle = Shape.rectangle(width: 30, height: 40)
switch circle{
case let .rectangle(10, x), let .squar(width1: 10, height1: x):
    print(x)
default:
    print("nil")
}

注意,前后变量要一一对应。不关注的也以用_来省略

枚举的嵌套

枚举中含有枚举
 enum CombineDirect{
    enum BaseDirect{
        case up
        case down
        case left
        case right
    }
    case leftUp(combineElement1: BaseDirect, combineElement2: BaseDirect)
    case rightUp(combineElement1: BaseDirect, combineElement2: BaseDirect)
    case leftDown(combineElement1: BaseDirect, combineElement2: BaseDirect)
    case rightDown(combineElement1: BaseDirect, combineElement2: BaseDirect)
}
let combind = CombineDirect.leftDown(combineElement1: .left, combineElement2: .down)
结构体中包含枚举
struct Skill{
    enum KeyType{
        case up
        case down
        case left
        case right
    }
    let key: KeyType
    func launchSkill(){
        switch key {
        case .left,.right:
            print("left, right")
        case .down,.up:
            print("up, down")
        }
    }
}

枚举中包含属性

enum 中能包含计算属性,类型属性。不能包含存储属性

 enum Shape{
    case circle(radious: Double)
    case rectangle(width: Int, height: Int)
//    var radious: Double
    static var height = 20.0
    var width: Double{
        get{
            return 10.0
        }
    }
}

枚举中包含方法

enum week: Int {
    case MON, TUE, WED, THU, FRI , SAT, SUN
    
    mutating func nextDay(){
        if self == .SUN{
            self = week(rawValue: 0)!
        }else{
            self = week(rawValue: self.rawValue + 1)!
        }
    }
}

枚举的大小

枚举的大小取决于枚举值,默认是UInt8大小,也就是一字节,超过UInt8容量就会升级为UInt16,也就是二字节,以此类推。
存在关联值,取决最大case的大小


 enum Shape{
    case circle(radious: Double)
    case rectangle(width: Int)
}

print(MemoryLayout<Shape>.stride)
print(MemoryLayout<Shape>.size)
·····
16
9

Double占8字节,加上case的1字节,就是9字节,根据字节对齐,所以步长是16。

indirect

enum List<T>{
    case end
    indirect case node(T, next: List<T>)
}

print(MemoryLayout<List<String>>.size)
print(MemoryLayout<List<String>>.stride)
·············
8
8

打印添加了indirect的枚举大小为8字节

var node = List<Int>.node(10, next: List<Int>.end)
·················
(lldb) p withUnsafePointer(to: &node, {$0})
(UnsafePointer<swiftTest.List<Int>>) $R6 = 0x0000000100003068
(lldb) x/4g 0x0000000100003068
0x100003068: 0x0000000100419fd0 0x00007fff98c81218
0x100003078: 0x00007fff98c81218 0x00000001007824d0
(lldb) x/4g 0x0000000100419fd0
0x100419fd0: 0x0000000100002030 0x0000000000000002
0x100419fe0: 0x000000000000000a 0x0000000000000000

通过打印地址,发现把声明了indirect关键字的值放在了堆空间上。
查看sil

// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @main.node : main.List<Swift.Int>        // id: %2
  %3 = global_addr @main.node : main.List<Swift.Int> : $*List<Int> // user: %16
  %4 = metatype $@thin List<Int>.Type
  %5 = integer_literal $Builtin.Int64, 10         // user: %6
  %6 = struct $Int (%5 : $Builtin.Int64)          // user: %13
  %7 = metatype $@thin List<Int>.Type
  %8 = enum $List<Int>, #List.end!enumelt         // user: %14
  %9 = alloc_box $<τ_0_0> { var (τ_0_0, next: List<τ_0_0>) } <Int> // users: %15, %10
  %10 = project_box %9 : $<τ_0_0> { var (τ_0_0, next: List<τ_0_0>) } <Int>, 0 // users: %12, %11
  %11 = tuple_element_addr %10 : $*(Int, next: List<Int>), 0 // user: %13
  %12 = tuple_element_addr %10 : $*(Int, next: List<Int>), 1 // user: %14
  store %6 to %11 : $*Int                         // id: %13
  store %8 to %12 : $*List<Int>                   // id: %14
  %15 = enum $List<Int>, #List.node!enumelt.1, %9 : $<τ_0_0> { var (τ_0_0, next: List<τ_0_0>) } <Int> // user: %16
  store %15 to %3 : $*List<Int>                   // id: %16
  %17 = integer_literal $Builtin.Int32, 0         // user: %18
  %18 = struct $Int32 (%17 : $Builtin.Int32)      // user: %19
  return %18 : $Int32                             // id: %19
} // end sil function 'main'

通过官方文档可以查看alloc_box的解释

Allocates a reference-counted @box on the heap large enough to hold a value of type T, along with a retain count and any other metadata required by the runtime. The result of the instruction is the reference-counted @box reference that owns the box. The project_box instruction is used to retrieve the address of the value inside the box.
在堆上分配一个引用计数的@box,其大小足以容纳类型T的值,以及retain计数和运行时所需的任何其他元数据。该指令的结果是引用计数的@box引用,该引用拥有该框。project_box指令用于检索框内值的地址。

OC-Swift混编

我们在Swift的枚举前加上@objc就可以了

@objc enum WEEK: Int {
    case MON, TUE
}

编译一下,我们就可以在.h文件中查看


查看转译文件.png
typedef SWIFT_ENUM(NSInteger, WEEK, closed) {
  WEEKMON = 0,
  WEEKTUE = 1,
};

OC仅能使用声明为Int类型的。

NS_ENUM
**********OC**********
NS_ENUM(NSInteger, OCENUM){
    Value1,
    Value2
};


**********SWIFT**********
public var OCENUM: OCENUM

public enum OCENUM : Int {

    
    case Value1 = 0

    case Value2 = 1
}
typedef enum

如果用typedef enum来声明,就会编译成结构体

**********OC**********
typedef enum {
    Num1,
    Num2
} OCNum;
**********SWIFT**********
public struct OCNum : Equatable, RawRepresentable {

    public init(_ rawValue: UInt32)

    public init(rawValue: UInt32)

    public var rawValue: UInt32
}
typedef NS_ENUM
**********OC**********
typedef NS_ENUM(NSInteger, CEnum) {
    CEnumInvalid = 0,
    CEnumA = 1,
    CEnumB,
    CEnumC
};
**********SWIFT**********
public enum CEnum : Int {

    
    case invalid = 0

    case A = 1

    case B = 2

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

推荐阅读更多精彩内容