Swift枚举熟练运用必备知识

Swift中的枚举有原始值和关联值,其使用范围相比OC来说多了很多,因此也更复杂,需要我们花更多的时间来学习它,本文是对学习后和在实际中的运用做的一个总结。
目前来看需要掌握的内容如下:

Swift枚举内容.jpg

一、Swift枚举声明
>>> A. 枚举的类型及原始值、关联值
    1. 声明枚举时,类型继承列表(即冒号后面)写原始值类型,不写时默认是Int,如果是其它类型则需要写明。
    1. 原始值代表的是一个枚举变量的rawValuerawValue的本质是枚举的计算属性
    1. 在写枚举的case时:
      如果原始值类型是IntString类型,不写明原始值会自动生成原始值, 对于Int类型默认从0开始,下一个是上一个case的原始值+1;对于String类型,默认原始值是case名;
      如果是其它原始值类型的枚举,可以用"="写明对应的原始值,见下面的Direction.
    1. 每个case后面可以追加枚举关联值,比如下面的Score.
    1. 递归枚举:如果枚举关联值中有枚举本身类型,则这个时候在枚举定义前或者case前需要加indirect
    1. 枚举变量初始化时使用一般使用enumName.caseName
    1. 枚举默认遵守RawRepresentable协议,协议里面有可失败初始化器init?(rawValue: Self.RawValue)和计算属性rawValue. 所以我们可以通过这个协议的方法来完成初始化和获取原始值rawValue
    1. 枚举的原始值类型必须是可以用字面量表示的,比如IntFloatString等, 不然的话会报错Raw value for enum case must be a literal.
    1. 枚举的case不能即写明原始值又写关联值,写了报错Enum with raw type cannot have cases with arguments
// 1.这里的原始值类型是Character,如果不写明= "d"则会报错. 
// 2.如果是不写原始值类型Character,默认是Int。
// 3.对于原始值类型是Int或者String,不写明“=”后面的也不会报错。
enum Direction: Character { 
    case north = "d"
    case south = "s"
    case east = "e"
    case west = "w"
}

// 带枚举关联值的枚举
enum Score {
    case point(Int, Int, Int)
    case grade(Character)
}

// case中关联值有自身枚举类型的递归枚举
indirect enum ArithExpr {
    case number(Int)
    case sum(ArithExpr, ArithExpr)
    case difference(ArithExpr, ArithExpr)
}
>>> B. 枚举的其它性质

Swift中枚举可以遵守协议,可以添加成员方法、静态方法、静态变量、计算属性。

enum BasketballNum4: Character, CaseIterable {
    case AAAA16 = "2"
    // 可添加计算属性
    var name: String { "dandy" }
    // 可添加静态变量
    static var name2: String { "dandy.static" }
    // 可添加成员方法
    func testSelf() {
        print(self.name)
        print(Self.name2)
    }
    // 可添加静态方法
    static func testSelf2() {
        print(self.name2)
    }
}
二、枚举变量的内存

弄清楚枚举的内存使用情况能让我们在使用时对性能消耗有所了解。
使用MemoryLayout可以查看分配内存和使用内存情况,比如下面的方式:

    print("MemoryLayout<String>.size", MemoryLayout<String>.size)
    print("MemoryLayout<String>.stride=", MemoryLayout<String>.stride)
    print("MemoryLayout<String>.alignment=", MemoryLayout<String>.alignment)
2.1 关联值的存储
  • 如果没有枚举关联值时,枚举变量只占一个字节,这个字节里面的内容就是case的序号。
  • 如果有枚举关联值,那么枚举内存分配 = 各个关联值类型所占的字节总和 + 1(这1个字节是存放枚举case序号的)+ 根据内存对齐alignment补齐字节。
  • 内存对齐alignment是关联值类型中最大的那个。
    证明过程:
    我这里是学习李明杰大师的方法做的,使用他的demo就可以实现:https://github.com/CoderMJLee/Mems
    打开demo --》在main文件顶部写showEnum() --》运行程序 --》打印枚举变量地址 --》如图打开内存面板,输入这个变量的地址值 --》 即可查看该内存里面的值。
    枚举关联值的存储.jpg
2.2 原始值的存储

rawValue是一个计算属性,在编译时就已经确定了每个枚举值对应的rawValue值,不需要存储。证明方法: 可以分析swift文件编译过程生成的中间文件sil
可以参考文章:Swift进阶(六)枚举和可选类型

2.3 枚举中方法、计算属性在内存中什么位置?
    1. 计算属性也可以认为是方法,方法的本质就是函数, 方法、函数都存放在代码段,所以计算属性、成员方法都存放在代码段。
    1. 静态变量就是全局变量,存放在内存的数据段。
    1. 静态方法存放在代码段。
      证明方法见博客Swift 方法及方法在内存中的位置
三、Swift枚举应用举例
    1. 跟OC语言枚举一样的情况,比如订单状态枚举。
    1. 应用于将多个相似的方法整合成一个,比如:RxSwift中的信号发送。
// 在OC中是分别有onNext、onComplete、onError三个方法,RxSwift的内部中转方法只使用一个on
func on(_ event: Event<Element>)
public enum Event<Element> {
    /// Next element is produced.
    case next(Element)
    /// Sequence terminated with an error.
    case error(Swift.Error)
    /// Sequence completed successfully.
    case completed
}
    1. 系统的可选类型也是一个枚举。可选类型可以赋值为nil,相当于赋值了Optional.none, 原因是遵守了ExpressibleByNilLiteral协议。
    1. 将APP所有的通知名集中到一个枚举中,枚举原始值类型声明为String,这样在使用直接用点语法找case,而且APP中包含哪些通知也变得一目了然。
    1. 埋点神策事件时使用枚举关联值来做,代码设计感会很不错。
    1. 网络请求使用Moya来实现的话,一个请求对应相关联参数,这个也可以用枚举关联值来做。
四、OC中使用Swift枚举

OC文件中导入#import "项目名-Swift.h"文件后去使用。

'@objc' enum must declare an integer raw type.
枚举原始值类型为Int的Swift枚举才允许在OC中使用,并且Swift枚举前需要加@objc。注意:OC中Integer就是Swift中的Int。

五、Swift中使用OC枚举

将OC枚举所在的文件导入到桥接文件中项目名-Bridging-Header.h
Swift中用枚举类型名 + 点语法就可以了。

OC中定义字符串枚举:
Apple官方的做法

.h 文件中
typedef NSString *AddressRecType NS_STRING_ENUM;

FOUNDATION_EXPORT AddressRecType const AddressRecTypeHistory;
FOUNDATION_EXPORT AddressRecType const AddressRecTypeCurrentLocation;
FOUNDATION_EXPORT AddressRecType const AddressRecTypeRGeo;

.m 文件中
AddressRecType const AddressRecTypeHistory = @"history";
AddressRecType const AddressRecTypeCurrentLocation = @"curLocation";
AddressRecType const AddressRecTypeRGeo = @"RGeo";

.swift 文件中 --------------
let enum5 = AddressRecType.currentLocation

有些情况使用字符串枚举更合适,比如:你写一个Pod私有库需要提供给Swift新项目中业务方使用,他们使用的方式是需要取到这个枚举对应的一个字符串类型作为参数去发送请求,这个参数如果由业务方根据枚举做一层映射的话,这样业务方麻烦,也怕他们会写错。
这个时候可以在OC中定义字符串枚举后,在Swift中使用该枚举的rawValue来取得这个字符串就能避免这个问题。

  • Handle unknown values using "@unknown default"的问题
    在Swift中对OC枚举所有case都处理后,仍然会有警告:
    Switch covers known cases, but 'ToastType' may have additional unknown values. Handle unknown values using "@unknown default"
    就是提示还需要处理未来可能新增加的case. 对于我们枚举中已经确定不会增加新的case了,OC中可以使用NS_CLOSED_ENUM来定义稳定的枚举。
typedef NS_CLOSED_ENUM(int, ToastType) {
    ToastTypeNormal,         // 文字
    ToastTypeSucceed,        // 成功
    ToastTypeWarn,           // 警告
    ToastTypeError,          // 错误
    ToastTypeLoading       // 加载
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容