Optional
Optional
的本質(zhì)是?個(gè)enum
Optional當(dāng)前枚舉接收?個(gè)泛型參數(shù)说贝,有
none
和some
兩個(gè)case
作箍,?當(dāng)前some
的關(guān)聯(lián)值是傳入的Wrapped
下?兩種寫法是完全等價(jià)的
var age: Int? var age1: Optional<Int>
既然是枚舉东亦,也可以通過模式匹配來匹配對(duì)應(yīng)的值
var age: Int? = 10 switch age{ case .none: print("age的值:nil") case .some(10): print("age的值:\(age)") default: print("age的值:unKonwn") } //輸出以下結(jié)果: //age的值:Optional(10)
解包
涉及到
Optional
就要面臨解包的問題员辩。因?yàn)楫?dāng)前可選項(xiàng)是對(duì)值做了包裝频轿,如果當(dāng)前不為nil
偷仿,需要從中拿到需要的值
強(qiáng)制解包
var age: Int? = 10 print(age!) //輸出以下結(jié)果: //10
使用強(qiáng)制解包,好處是省事衣屏,壞處是當(dāng)前
age
為nil
躏升,程序就會(huì)崩潰
程序崩潰
if let
var age: Int? = nil if let unWrappedValue = age { print("value: \(unWrappedValue)") } else { print("age為nil") } //輸出以下結(jié)果: //age為nil
- 使?
if let
是通過可選項(xiàng)綁定的?式,判斷當(dāng)前可選項(xiàng)是否有值- 使?
if let
定義的unWrappedValue
僅能在當(dāng)前if
分?的?括號(hào)內(nèi)訪問
guard let
func test(_ age: Int?) { guard let unWrappedValue = age else { print("age為nil") return } print(unWrappedValue) } test(nil) //輸出以下結(jié)果: //age為nil
- 使用
guard let
的判斷條件為false
狼忱,才會(huì)執(zhí)??括號(hào)內(nèi)的代碼膨疏,反之執(zhí)?后?的代碼- 使用
guard let
定義的unWrappedValue
在當(dāng)前?括號(hào)外部也能訪問guard
需要return
或throw
配合使用,達(dá)到不符合條件時(shí)提前退出的目的
將上面代碼中的
return
注釋掉钻弄,編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
Equatable
Swift
中的類型佃却,可以通過遵循Equatable
協(xié)議,使?相等運(yùn)算符==
和不等運(yùn)算符!=
窘俺,用來?較兩個(gè)值相等還是不相等饲帅。Swift
標(biāo)準(zhǔn)庫(kù)中絕?多數(shù)的類型都默認(rèn)實(shí)現(xiàn)了Equatable
協(xié)議
比如
Int
類型,系統(tǒng)默認(rèn)實(shí)現(xiàn)了==
var age1: Int = 10 var age2: Int = 20 var isEqual = age1 == age2 print(isEqual) //輸出以下結(jié)果: //false
Optional
類型瘤泪,同樣遵循了Equatable
協(xié)議灶泵,并重載了==
運(yùn)算符
var age1: Int? = 10
var age2: Optional<Int> = Optional(10)
var isEqual = age1 == age2
print(isEqual)
//輸出以下結(jié)果:
//true
上述代碼,可以對(duì)
Optional
類型直接使用==
判斷
遵循
Equatable
協(xié)議均芽,實(shí)現(xiàn)?定類型的==
運(yùn)算符
struct LGTeacher: Equatable {
var age: Int
var name: String
}
var t1 = LGTeacher(age: 18, name: "Zang")
var t2 = LGTeacher(age: 18, name: "Zang")
var isEqual = t1 == t2
print(isEqual)
//輸出以下結(jié)果:
//true
通過打印可以看到丘逸,系統(tǒng)能夠正確判斷出
t1
、t2
兩個(gè)結(jié)構(gòu)體是否相等掀宋,也就意味著系統(tǒng)默認(rèn)實(shí)現(xiàn)==
運(yùn)算符
將上述代碼生成SIL文件:
swiftc -emit-sil main.swift | xcrun swift-demangle
__derived_struct_equalsbb0bb1bb4
如果是結(jié)構(gòu)體中嵌套結(jié)構(gòu)體深纲,內(nèi)嵌結(jié)構(gòu)體也要遵循
Equatable
協(xié)議,否則編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
struct LGTeacher: Equatable {
var age: Int
var name: String
var child: LGChild
}
struct LGChild: Equatable {
var age: Int
var name: String
}
var t1 = LGTeacher(age: 18, name: "Zang", child: LGChild(age: 10, name: "Child"))
var t2 = LGTeacher(age: 18, name: "Zang", child: LGChild(age: 10, name: "Child"))
var isEqual = t1 == t2
print(isEqual)
//輸出以下結(jié)果:
//true
上述代碼劲妙,只有
LGTeacher
和LGChild
都遵循Equatable
協(xié)議湃鹊,才能使用==
運(yùn)算符
如果是
Class
,除了遵循Equatable
協(xié)議镣奋,還要自行實(shí)現(xiàn)func ==
方法币呵,否則編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
class LGTeacher: Equatable {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
static func == (lhs: LGTeacher, rhs: LGTeacher) -> Bool {
return lhs.age == rhs.age && lhs.name == rhs.name
}
}
var t1 = LGTeacher.init(age: 18, name: "Zang")
var t2 = LGTeacher.init(age: 18, name: "Zang")
var isEqual = t1 == t2
print(isEqual)
//輸出以下結(jié)果:
//true
上述代碼,
Class
必須自行實(shí)現(xiàn)func ==
方法,才能使用==
運(yùn)算符
==
運(yùn)算符?來判斷值是否相等余赢,也就是equal to
芯义。如果判斷兩個(gè)對(duì)象是否是同?個(gè)實(shí)例對(duì)象,需要使用===
class LGTeacher: Equatable {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
static func == (lhs: LGTeacher, rhs: LGTeacher) -> Bool {
return lhs.age == rhs.age && lhs.name == rhs.name
}
}
var t1 = LGTeacher.init(age: 18, name: "Zang")
var t2 = LGTeacher.init(age: 18, name: "Zang")
var isEqual1 = t1 == t2
var isEqual2 = t1 === t2
print(isEqual1)
print(isEqual2)
//輸出以下結(jié)果:
//true
//false
Comparable
Comparable
自動(dòng)遵循Equatable
協(xié)議妻柒,支持更多比較方式
public protocol Comparable : Equatable {
static func < (lhs: Self, rhs: Self) -> Bool
static func <= (lhs: Self, rhs: Self) -> Bool
static func >= (lhs: Self, rhs: Self) -> Bool
static func > (lhs: Self, rhs: Self) -> Bool
}
遵循
Comparable
協(xié)議扛拨,還要自行實(shí)現(xiàn)func <
方法,否則編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
遵循
Comparable
協(xié)議實(shí)現(xiàn)func <
方法举塔,編譯器會(huì)通過<
自動(dòng)實(shí)現(xiàn)其它運(yùn)算符
struct LGTeacher: Comparable {
var age: Int
var name: String
static func < (lhs: LGTeacher, rhs: LGTeacher) -> Bool {
return lhs.age < rhs.age
}
}
var t1 = LGTeacher(age: 20, name: "Zang")
var t2 = LGTeacher(age: 18, name: "Zang")
var isEqual1 = t1 < t2
var isEqual2 = t1 > t2
print(isEqual1)
print(isEqual2)
//輸出以下結(jié)果:
//false
//true
上述代碼绑警,實(shí)現(xiàn)
func <
方法,<
央渣、<=
计盒、>=
、>
等運(yùn)算符都能使用
空合運(yùn)算符(??)
var age: Int?
print("age:\(age1 ?? 10)")
//輸出以下結(jié)果:
//age:10
上述代碼芽丹,如果
age
為nil
北启,返回10
空合運(yùn)算符在源碼中有兩個(gè)方法,一個(gè)返回
T
拔第,一個(gè)返回T?
返回T返回T?這兩個(gè)方法的調(diào)用暖庄,跟空合運(yùn)算符后面的返回值類型有關(guān)
- 如果返回的是非可選類型,調(diào)用上面返回
T
的方法- 如果是返回是可選類型楼肪,調(diào)用下面返回
T?
的方法
var age1: Int?
var age2: Int? = 20
var tmp = age1 ?? age2
print("tmp:\(tmp)")
//輸出以下結(jié)果:
//tmp:Optional(20)
上述代碼,
age2
是可選類型惹悄,返回的就是T?
空合運(yùn)算符后面返回值的類型春叫,還要跟當(dāng)前值的類型保持一致。當(dāng)前值是
Int
類型泣港,就不能返回String
類型暂殖,否則編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
可選鏈
可選鏈:允許在鏈上通過可選項(xiàng)去訪問屬性、方法
class LGTeacher {
var name: String? = "LGTeacher"
var child: LGChild?
}
class LGChild {
var name: String? = "LGChild"
}
var t: LGTeacher? = LGTeacher()
if let name = t?.child?.name {
print(name)
}
上述代碼当纱,無論
t
或child
哪個(gè)值為nil
呛每,后面的鏈?zhǔn)秸{(diào)用都不會(huì)執(zhí)行,直接返回nil
class LGTeacher {
var name: String? = "LGTeacher"
var child: LGChild?
}
class LGChild {
var name: String? = "LGChild"
func test() {
print("test")
}
}
var t: LGTeacher? = LGTeacher()
t?.child?.test()
上述代碼坡氯,對(duì)于方法也是一樣的晨横,無論
t
或child
哪個(gè)值為nil
,后面的test
方法都不會(huì)被調(diào)用
unsafelyUnwrapped
unsafelyUnwrapped
和強(qiáng)制解包的作用一致箫柳,但Release
模式下又有一些區(qū)別
var age: Int? = 30
print(age!)
print(age.unsafelyUnwrapped)
//輸出以下結(jié)果:
//30
//30
上述代碼手形,使用
age!
和age.unsafelyUnwrapped
效果完全一樣,打印結(jié)果都是30
如果
age
的值是nil
悯恍,使用age.unsafelyUnwrapped
訪問库糠,同樣是程序崩潰
程序崩潰
unsafelyUnwrapped
和強(qiáng)制解包在Release
模式下的一些區(qū)別
Release模式使用
age!
強(qiáng)制解包,程序崩潰
age!使用
age.unsafelyUnwrapped
涮毫,程序沒有崩潰瞬欧,打印結(jié)果0
age.unsafelyUnwrapped
as
as
用于類型轉(zhuǎn)換贷屎,可以使用as
、as?
艘虎、as!
幾種方式
as
var age: Int = 10 var age1 = age as Any print(age1) //輸出以下結(jié)果: //10
使用
as
將Int
類型轉(zhuǎn)換為Any
唉侄、AnyObject
都沒問題。但轉(zhuǎn)換為Double
類型顷帖,編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
as?
var age: Int = 10 var age1 = age as? Double print(age1) //輸出以下結(jié)果: //nil
as?
可以避免編譯報(bào)錯(cuò)美旧,使用as?
返回的是可選項(xiàng),如果轉(zhuǎn)換失敗贬墩,直接返回nil
返回可選項(xiàng)
as!
var age: Int = 10 var age1 = age as! Double print(age)
使用
as!
強(qiáng)制類型轉(zhuǎn)換榴嗅,如果轉(zhuǎn)換失敗,程序直接崩潰
程序崩潰
訪問控制
在
OC
中很少接觸這個(gè)概念陶舞,但Swift
中針對(duì)源?件和模塊的代碼嗽测,提供不同程度的訪問控制
- 訪問級(jí)別由低到高:
private
<filePrivate
<internal
<public
<open
- 不指定訪問級(jí)別,默認(rèn)都是
internal
private
訪問級(jí)別僅在當(dāng)前定義的作?域內(nèi)有效
案例1:在
LGTeacher
中定義了?個(gè)private
變量肿孵,這時(shí)當(dāng)前變量的訪問控制權(quán)限唠粥,僅在這個(gè)類定義的作?域內(nèi)有效。如果在當(dāng)前作?域之外訪問停做,編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
案例2:
Swift
單例的正確寫法就是通過private
控制訪問權(quán)限晤愧,限制當(dāng)前init
?法,僅在這個(gè)類定義的作?域內(nèi)有效class LGTeacher{ static let sha = LGTeacher() private init(){} } var t = LGTeacher.sha
filePrivate
此訪問限制僅限制在當(dāng)前定義的源?件中
案例1:在
access.swift
中定義LGTeacher
類蛉腌,訪問權(quán)限設(shè)置為fileprivate
官份。將全局變量t
聲明為LGTeacher
類型,編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)案例1的問題:變量
t
屬于全局變量烙丛,訪問權(quán)限是internal
舅巷,變量訪問權(quán)限高于類型訪問權(quán)限,所以編譯報(bào)錯(cuò)fileprivate class LGTeacher{ var age: Int = 10 } fileprivate var t1: LGTeacher = LGTeacher() private var t2: LGTeacher = LGTeacher()
上述代碼河咽,需要將變量訪問權(quán)限設(shè)置為
filePrivate
钠右,或級(jí)別更低的private
,才能聲明成功
案例2:在
access.swift
中定義LGTeacher
類忘蟹,將age
屬性設(shè)置為filePrivate
// access.swift class LGTeacher{ fileprivate var age: Int = 10 }
在
main.swift
中訪問age
屬性飒房,編譯報(bào)錯(cuò)
編譯報(bào)錯(cuò)
internal
默認(rèn)訪問級(jí)別,允許定義模塊中的任意源?件訪問寒瓦,但不能被該模塊之外的任何源?件訪問
模塊是指框架或應(yīng)用程序情屹,使用
import
導(dǎo)入的框架都是模塊,例如Foundation
import Foundation
public
開放式訪問
- 允許任意模塊杂腰、任意源?件的訪問
- 只能在定義的模塊中繼承和?類重寫
open
最不受限制的訪問級(jí)別
- 允許任意模塊垃你、任意源?件的訪問
- 允許任意模塊中繼承和?類重寫