本文源自本人的學(xué)習(xí)記錄整理與理解艺骂,其中參考閱讀了部分優(yōu)秀的博客和書籍,盡量以通俗簡(jiǎn)單的語句轉(zhuǎn)述隆夯。引用到的地方如有遺漏或未能一一列舉原文出處還望見諒與指出钳恕,另文章內(nèi)容如有不妥之處還望指教,萬分感謝蹄衷。
枚舉
枚舉的基本用法
enum Direction {
case north
case south
case east
case west
}
-------------兩段代碼等價(jià)--------------
enum Direction {
case north, south, east, west
}
- 關(guān)聯(lián)值(Associated Values)
- 有時(shí)會(huì)將枚舉的
成員值
跟其他類型
的值關(guān)聯(lián)存儲(chǔ)在一起
忧额,會(huì)非常有用
特點(diǎn):關(guān)聯(lián)值可以隨意修改,枚舉所占內(nèi)存大小跟關(guān)聯(lián)值有直接關(guān)系
Int : 關(guān)聯(lián)值類型是Int
(Int,Int,Int,Int):關(guān)聯(lián)值
enum PokerSuit : Int {
case spade(Int,Int,Int,Int)
case other
}
po: 枚舉變量
var po = PokerSuit. spade(11,22,33,44)
- 原始值(Raw Values)
枚舉成員可以使用相同類型
的默認(rèn)值
預(yù)先關(guān)聯(lián)愧口,這個(gè)默認(rèn)值叫做:原始值
特點(diǎn):原始值是固定的睦番,不可修改;不會(huì)占用枚舉變量內(nèi)存
, 因?yàn)樗淮鎯?chǔ)在枚舉變量內(nèi)存里
Character : 原始值類型是字符類型
"?":原始值
enum PokerSuit : Character {
case spade = "?"
case heart = "紅"
}
po: 枚舉變量
var po = PokerSuit. spade
這里的rawValue就是獲取枚舉成員的原始值
var rawValue = PokerSuit. spade.rawValue
- 隱式原始值(Implicitly Assigned Raw Values)
- 如果枚舉的原始值類型是Int 调卑、String 抡砂;Swift會(huì)自動(dòng)分配原始值
enum Direction :String {
case north = "north"
case south = "south"
case east = "east"
case west = "west"
}
-------------兩段代碼等價(jià)--------------
enum Direction :String {
case north, south, east, west
}
字符串的名字是什么,默認(rèn)關(guān)聯(lián)的值也就是這個(gè)字符串
Int類型關(guān)聯(lián)值會(huì)是:0恬涧、1注益、2搭幻、3
- 遞歸枚舉 (Recursive Enumeration), 枚舉前需要定義
indirect
關(guān)鍵字
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
- 可以使用
MemoryLayout
獲取數(shù)據(jù)類型占用的內(nèi)存大小
獲取Int類型在當(dāng)前架構(gòu)(arm64)實(shí)際使用內(nèi)存大小
MemoryLayout<Int>.size
獲取Int類型在當(dāng)前架構(gòu)(arm64)分配的內(nèi)存大小
MemoryLayout<Int>.stride
內(nèi)存對(duì)齊參數(shù)
MemoryLayout<Int>.alignment
var age = 20
MemoryLayout.size(ofValue: age)
MemoryLayout.stride(ofValue: age)
MemoryLayout.alignment(ofValue: age)
可選項(xiàng)
- 可選項(xiàng)垢揩,一般也叫做可選類型递宅;特點(diǎn):它允許將值設(shè)置為
nil
,普通的可變類型初始化之后,賦值為nil
編譯器會(huì)直接報(bào)錯(cuò) - 多應(yīng)用在不確定情況的場(chǎng)景
- 在類型名稱后面加一個(gè)問好
?
來定義一個(gè)可選項(xiàng) - 本質(zhì):可選項(xiàng)是對(duì)其他類型的一層包裝杀捻,可以將它理解為一個(gè)盒子
- 如果為
nil
, 那么它是個(gè)空盒子,反之盒子里包裝的是:被包裝的類型數(shù)據(jù)
var name: String? = "逍遙侯"
name = nil
------------------------------------
var age:Int? //默認(rèn)就是nil
age = 10
age = nil
------------------------------------
利用可選類型適配數(shù)組越界
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
強(qiáng)制解包(Forced Unwrapping)
如果要從可選項(xiàng)中取出被包裝的數(shù)據(jù)(將盒子里包裝的東西取出來)俩由,需要使用感嘆號(hào) 嫉髓!進(jìn)行強(qiáng)制解包
強(qiáng)制解包值是訪問盒子中的值,不會(huì)對(duì)盒子有影響
如果對(duì)值為
nil
的可選項(xiàng)進(jìn)行強(qiáng)制解包谎仲,會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤
var age:Int? //默認(rèn)就是nil
age = 10
var hhage: Int = age!
hhage += 10
輸出:20
- 判斷可選項(xiàng)是否包含值
//字符串轉(zhuǎn)Int浙垫,可能轉(zhuǎn)換成功(整數(shù)),也可能轉(zhuǎn)換失斨E怠(nil)
let number = Int("224") //number是 number夹姥?,即可選類型辙诞;
//轉(zhuǎn)換失敗number=nil, 反之成功
if number != nil {
print("字符串轉(zhuǎn)換整數(shù)成功:\(number!)") //強(qiáng)制解包
} else {
print("字符串轉(zhuǎn)換整數(shù)失敗")
}
- 可選項(xiàng)綁定(Optional Binding)
- 可以使用
可選項(xiàng)綁定
來判斷可選項(xiàng)是否包含值- 如果包含就自動(dòng)解包辙售,把值賦給一個(gè)臨時(shí)的常量(
let
)或者變量(var
),并返回ture
,否則返回false
- 如果包含就自動(dòng)解包辙售,把值賦給一個(gè)臨時(shí)的常量(
//先將字符串強(qiáng)制轉(zhuǎn)換為Int ,如果成功返回一個(gè)包含224的可選項(xiàng),并自動(dòng)解包飞涂,最終會(huì)把224這個(gè)數(shù)值賦值給number旦部;條件判斷返回ture ; 反之返回false
if let number = Int("224") {
print("字符串轉(zhuǎn)換整數(shù)成功:\(number!)") //強(qiáng)制解包
} else {
print("字符串轉(zhuǎn)換整數(shù)成功")
}
- 可選項(xiàng)綁定
等價(jià)寫法
: 使用逗號(hào)(,
)隔開; 不能夠使用&&
- while循環(huán)中使用可選項(xiàng)綁定
示例:
遍歷數(shù)組,將遇到的正數(shù)都加起來较店,如果遇到負(fù)數(shù)或者非數(shù)字士八,則停止遍歷返回
var strs = ["10","13","18","abj","-2","19","0",]
var index = 0
var sum = 0
可選項(xiàng)綁定,且num大于零; 逗號(hào)表示兩個(gè)條件要同時(shí)成立
while let num = Int(strs[index]), num > 0 {
sum += num
index += 1
}
print(sum)
- 空合運(yùn)算符: ?? (Nil - Coalescing Operator)
空合運(yùn)算符源碼定義
public func ?? <T>(optional: T?, defaultValue: @autoclosure () thorws - > T?) rethrows - > T?
public func ?? <T>(optional: T?, defaultValue: @autoclosure () thorws - > T) rethrows - > T?
簡(jiǎn)單用法:
a
?? b
a : 要求必須是可選項(xiàng)梁呈;如果不是編譯器會(huì)報(bào)??曹铃,不建議這么寫
b和a的存儲(chǔ)類型必須相同
b : 是可選項(xiàng) 或者 不是可選項(xiàng)
b是可選項(xiàng):
如果a不為nil
,就返回 a
如果a為nil
捧杉,就返回 b
b不是可選項(xiàng) :
如果a不為nil
陕见,就返回a盒子中的值; 且返回a時(shí)會(huì)自動(dòng)解包
如果a為nil
,就返回b
結(jié)論:空合運(yùn)算返回的類型取決于b的類型味抖,b是什么類型最終就返回什么類型
- 多個(gè)
??
一起使用; 規(guī)則從左到右運(yùn)算
示例:
let a: Int? = 1
let b: Int? = 2
let c = a ?? b ?? 3
分析: 首先會(huì)先運(yùn)算a??b, 因?yàn)閍不為空且b是可選類型评甜,所以返回可選類型a, 然后 a??3 , a不為空,3不是可選類型仔涩,最終解包a盒子中的值1忍坷;
所以c是Int類型 值為1
-
??
跟if let
配合使用
獲取兩個(gè)可選類型中有值得哪一個(gè)
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
語句佩研,當(dāng)要使用多次if
判斷時(shí),可以考慮是用guard
代替
注意:做完事情必須退出作用域霞揉,可以使用關(guān)鍵字:return
旬薯、break
、continue
适秩、throw
绊序、error
- 當(dāng)
guard
語句的條件為false
時(shí)硕舆,就會(huì)執(zhí)行大括號(hào)里面的代碼 ? - 當(dāng)
guard
語句的條件為true
時(shí)骤公,就會(huì)跳過guard語句 -
guard
語句特別適合用來實(shí)現(xiàn)”提前退出
“ - 當(dāng)使用
guard
語句進(jìn)行可選項(xiàng)綁定
時(shí)抚官,綁定的常量、變量也能在外層作用域中使用
如下示例中username
和password
可以在外層作用域訪問
- 隱式解包 (Implicitly Unwrapped Optional)
- 在某些情況下阶捆,可選項(xiàng)一旦被設(shè)定值之后凌节,就會(huì)一直擁有值
- 在這種情況下,可以去掉檢查洒试,也不一定每次訪問的時(shí)候都進(jìn)行解包刊咳,因?yàn)樗艽_定每次訪問的時(shí)候都有值
- 可以在類型后面加個(gè)感嘆號(hào)
!
定義一個(gè)隱式解包的可選項(xiàng) - 感嘆號(hào)和問好都代表可選類型儡司,只不過問號(hào)需要強(qiáng)制解包后才能拿到盒子里的值,而感嘆號(hào)已經(jīng)自動(dòng)對(duì)可選類型進(jìn)行了解包余指,可以直接使用
隱式解包的可選項(xiàng)
let num: Int != 10
let num1: Int = num
- 字符串插值或空合運(yùn)算符捕犬,消除打印可選項(xiàng)的??
- 多重可選項(xiàng),可以是一個(gè)問號(hào)
?
酵镜、兩個(gè)問號(hào)??
碉碉、 三個(gè)問號(hào)???
- 可以使用lldb指令
frame variable -R
或者fr v -R
查看區(qū)別
包裝了一個(gè)Int類型的可選類型
var num1: Int? = 10
包裝了一個(gè)可選類型的可選類型,這里的??不代表空合運(yùn)算淮韭,需要注意
var num2: Int?? = num1
包裝了Int類型可選類型的可選類型, 這樣寫就等同于num2
var num3: Int?? = 30
包裝了空的可選類型
var num1: Int? =nil
包裝了一個(gè)空的可選類型的可選類型垢粮,這里的??不代表空合運(yùn)算,需要注意
var num2: Int?? = num1
包裝了大的空可選類型
var num3: Int?? = nil