Swift~枚举、可选项

本文源自本人的学习记录整理与理解,其中参考阅读了部分优秀的博客和书籍,尽量以通俗简单的语句转述。引用到的地方如有遗漏或未能一一列举原文出处还望见谅与指出,另文章内容如有不妥之处还望指教,万分感谢。

枚举

枚举的基本用法


enum Direction {
case north
case south
case east
case west
}

-------------两段代码等价--------------

enum Direction {
case north, south, east, west
}

基本用法.png
  • 关联值(Associated Values)
  1. 有时会将枚举的成员值其他类型的值关联存储在一起,会非常有用
    特点:关联值可以随意修改,枚举所占内存大小跟关联值有直接关系
y4828.png

Int : 关联值类型是Int
(Int,Int,Int,Int):关联值

enum PokerSuit : Int {
case spade(Int,Int,Int,Int)
case other
}

po: 枚举变量
var po = PokerSuit. spade(11,22,33,44)

  • 原始值(Raw Values)

枚举成员可以使用相同类型默认值预先关联,这个默认值叫做:原始值
特点:原始值是固定的,不可修改;不会占用枚举变量内存, 因为它不存储在枚举变量内存里

Character : 原始值类型是字符类型
 "♠":原始值
enum PokerSuit : Character {
case spade  = "♠"
case heart  = "红"
}

po: 枚举变量
var po = PokerSuit. spade

这里的rawValue就是获取枚举成员的原始值
var rawValue = PokerSuit. spade.rawValue


  • 隐式原始值(Implicitly Assigned Raw Values)
  1. 如果枚举的原始值类型是Int 、String ;Swift会自动分配原始值

enum Direction :String {
case north = "north"
case south = "south"
case east = "east"
case west = "west"
}

-------------两段代码等价--------------

enum Direction :String {
case north, south, east, west
}

字符串的名字是什么,默认关联的值也就是这个字符串
Int类型关联值会是:0、1、2、3

  • 递归枚举 (Recursive Enumeration), 枚举前需要定义 indirect 关键字

indirect enum ArithExpr {
    case number(Int)
    case sum(ArithExpr, ArithExpr)
    case differ(ArithExpr, ArithExpr)
}

---------------两段代码等同----------------

 enum ArithExpr {
    case number(Int)
   indirect case sum(ArithExpr, ArithExpr)
   indirect case differ(ArithExpr, ArithExpr)
}

  • MemoryLayout
  1. 可以使用MemoryLayout获取数据类型占用的内存大小
获取Int类型在当前架构(arm64)实际使用内存大小
MemoryLayout<Int>.size

获取Int类型在当前架构(arm64)分配的内存大小
MemoryLayout<Int>.stride

内存对齐参数
MemoryLayout<Int>.alignment


var age = 20
MemoryLayout.size(ofValue: age)
MemoryLayout.stride(ofValue: age)
MemoryLayout.alignment(ofValue: age)

MemoryLayout.png

可选项

  • 可选项,一般也叫做可选类型;特点:它允许将值设置为nil,普通的可变类型初始化之后,赋值为nil编译器会直接报错
  • 多应用在不确定情况的场景
  • 在类型名称后面加一个问好 ? 来定义一个可选项
  • 本质:可选项是对其他类型的一层包装,可以将它理解为一个盒子
  • 如果为nil , 那么它是个空盒子,反之盒子里包装的是:被包装的类型数据

var name: String? = "逍遥侯"
name = nil

------------------------------------

var age:Int? //默认就是nil
age = 10
age = nil

------------------------------------

利用可选类型适配数组越界

var  list = [1,2,4,9]
func get(_ index: Int) ->Int?
{
      if index < 0 || index >= list.count {
             return nil
      }
    return list[index]
}

print(get(1))   //Optional(15)
print(get(-1)) //nil
print(get(4))  //nil

可选类型和不可选类型的区别.png
  • 强制解包(Forced Unwrapping)

  • 如果要从可选项中取出被包装的数据(将盒子里包装的东西取出来),需要使用感叹号 !进行强制解包

  • 强制解包值是访问盒子中的值,不会对盒子有影响

  • 如果对值为nil的可选项进行强制解包,会产生运行时错误


var age:Int? //默认就是nil
age = 10

var hhage: Int = age!

hhage += 10

输出:20

  • 判断可选项是否包含值

//字符串转Int,可能转换成功(整数),也可能转换失败(nil)
let number = Int("224") //number是 number?,即可选类型;

//转换失败number=nil, 反之成功
if number != nil {

print("字符串转换整数成功:\(number!)")  //强制解包

} else {

print("字符串转换整数失败")

}

  • 可选项绑定(Optional Binding)
  1. 可以使用可选项绑定来判断可选项是否包含值
    • 如果包含就自动解包,把值赋给一个临时的常量(let)或者变量(var),并返回ture,否则返回false

//先将字符串强制转换为Int ,如果成功返回一个包含224的可选项,并自动解包,最终会把224这个数值赋值给number;条件判断返回ture ; 反之返回false

if  let number = Int("224") {

print("字符串转换整数成功:\(number!)")  //强制解包

} else {

print("字符串转换整数成功")

}

  • 可选项绑定等价写法: 使用逗号(,)隔开; 不能够使用 &&
等价写法.png
  • while循环中使用可选项绑定

示例:

遍历数组,将遇到的正数都加起来,如果遇到负数或者非数字,则停止遍历返回

var strs = ["10","13","18","abj","-2","19","0",]
var index = 0
var sum = 0

可选项绑定,且num大于零; 逗号表示两个条件要同时成立
while let num = Int(strs[index]), num > 0 {

sum += num

index += 1

}

print(sum)

  • 空合运算符: ?? (Nil - Coalescing Operator)

空合运算符源码定义

public func ?? <T>(optional: T?, defaultValue: @autoclosure () thorws - > T?) rethrows - > T?

public func ?? <T>(optional: T?, defaultValue: @autoclosure () thorws - > T) rethrows - > T?

简单用法:

a ?? b

a : 要求必须是可选项;如果不是编译器会报⚠️,不建议这么写
b和a的存储类型必须相同
b : 是可选项 或者 不是可选项

b是可选项:
如果a不为nil ,就返回 a

如果a为nil,就返回 b

b不是可选项 :
如果a不为nil ,就返回a盒子中的值; 且返回a时会自动解包
如果a为nil,就返回b

结论:空合运算返回的类型取决于b的类型,b是什么类型最终就返回什么类型

用例.png
  • 多个 ?? 一起使用; 规则从左到右运算

示例:


let a:  Int? = 1
let b: Int? = 2

let c = a ?? b ?? 3

分析: 首先会先运算a??b, 因为a不为空且b是可选类型,所以返回可选类型a, 然后 a??3 , a不为空,3不是可选类型,最终解包a盒子中的值1;
所以c是Int类型 值为1

  • ??if let 配合使用

获取两个可选类型中有值得哪一个


let a: Int? = nil
let b: Int? = 2

if let c = a ?? b {
  print(c)
}

//类似于 if a != nil  || b != nil 

-----------------------------

c绑定a,a不等于空,且 d绑定b,b不等于空
if  let c = a , let d = b {
  print(c)
  print(d)
}

//类似于if a != nil  && b != nil 

  • guard语句,当要使用多次if判断时,可以考虑是用guard代替
用法.png

注意:做完事情必须退出作用域,可以使用关键字:returnbreakcontinuethrowerror

  • guard语句的条件为false时,就会执行大括号里面的代码 ?
  • guard语句的条件为true时,就会跳过guard语句
  • guard语句特别适合用来实现”提前退出
  • 当使用guard语句进行可选项绑定时,绑定的常量、变量也能在外层作用域中使用

如下示例中usernamepassword可以在外层作用域访问

guard示例.png
  • 隐式解包 (Implicitly Unwrapped Optional)
  1. 在某些情况下,可选项一旦被设定值之后,就会一直拥有值
  2. 在这种情况下,可以去掉检查,也不一定每次访问的时候都进行解包,因为它能确定每次访问的时候都有值
  3. 可以在类型后面加个感叹号定义一个隐式解包的可选项
  4. 感叹号和问好都代表可选类型,只不过问号需要强制解包后才能拿到盒子里的值,而感叹号已经自动对可选类型进行了解包,可以直接使用

隐式解包的可选项
let num: Int != 10
let num1: Int = num

  • 字符串插值或空合运算符,消除打印可选项的⚠️
字符串插值解决可选项打印警告.png
  • 多重可选项,可以是一个问号 ? 、两个问号?? 、 三个问号???
  1. 可以使用lldb指令frame variable -R或者fr v -R查看区别

包装了一个Int类型的可选类型
var num1: Int? = 10

包装了一个可选类型的可选类型,这里的??不代表空合运算,需要注意
var num2: Int?? = num1

包装了Int类型可选类型的可选类型, 这样写就等同于num2
var num3: Int?? = 30

原理图.png

包装了空的可选类型
var num1: Int? =nil

包装了一个空的可选类型的可选类型,这里的??不代表空合运算,需要注意
var num2: Int?? = num1

包装了大的空可选类型
var num3: Int?? = nil

原理图1.png

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

推荐阅读更多精彩内容