var释簿、let
var聲明變量亚隅,表示變量可修改,如var a = 3庶溶,可以對(duì)a進(jìn)行修改煮纵,a=4
let聲明變量,表示變量不可修改偏螺,如let a = 3行疏,那么就不可以對(duì)a進(jìn)行修改(a=4報(bào)錯(cuò))
簡(jiǎn)單來(lái)說(shuō),var表示這個(gè)變量套像,可以指向新的內(nèi)存地址酿联,而let,則不能指向新的內(nèi)存地址
staic、class贞让、final
static修飾的方法采幌,變量,表示靜態(tài)方法震桶、變量,可以用于結(jié)構(gòu)體征绎、協(xié)議蹲姐、類(lèi)中,而在類(lèi)中使用時(shí)人柿,它和它的子類(lèi)共享柴墩,但是不能被子類(lèi)重寫(xiě)
class修飾的方法,變量凫岖,表示類(lèi)方法江咳、變量,只能用在類(lèi)中哥放,子類(lèi)可以重寫(xiě)歼指;
需要注意的是,class通常修飾方法甥雕,如果修飾變量的話踩身,只能是計(jì)算型變量。
final關(guān)鍵字在大多數(shù)的編程語(yǔ)言中都存在社露,表示不允許對(duì)其修飾的內(nèi)容進(jìn)行繼承或者重新操作挟阻。Swift中,final關(guān)鍵字可以在class峭弟、func和var前修飾附鸽。
defer
1、defer語(yǔ)句在代碼塊(方法瞒瘸、閉包等坷备,可以理解為大括號(hào)包裝起來(lái)的代碼)作用域退出之前執(zhí)行,也就是代碼塊中其他應(yīng)該執(zhí)行的代碼都執(zhí)行完了挨务,才執(zhí)行defer中的代碼
2击你、一個(gè)代碼塊允許多個(gè)defer,多個(gè)defer執(zhí)行的順序 從后到前
3谎柄、defer 語(yǔ)句塊中的代碼, 會(huì)在當(dāng)前作用域結(jié)束前調(diào)用, 常用場(chǎng)景如異常退出后, 關(guān)閉數(shù)據(jù)庫(kù)連接
4丁侄、需要注意的是, 如果有多個(gè) defer, 那么后加入的先執(zhí)行
func someQuery() -> ([Result], [Result]){
let db = DBOpen("xxx")
defer {
db.close()
}
guard results1 = db.query("query1") else {
return nil
}
guard results2 = db.query("query2") else {
return nil
}
return (results1, results2)
}</pre>
//需要注意的是, 如果有多個(gè) defer, 那么后加入的先執(zhí)行
func someDeferFunction() {
defer {
print("\(#function)-end-1-1")
print("\(#function)-end-1-2")
}
defer {
print("\(#function)-end-2-1")
print("\(#function)-end-2-2")
}
if true {
defer {
print("if defer")
}
print("if end")
}
print("function end")
}
someDeferFunction()
// 輸出
// if end
// if defer
// function end
// someDeferFunction()-end-2-1
// someDeferFunction()-end-2-2
// someDeferFunction()-end-1-1
// someDeferFunction()-end-1-2</pre>
dynamic
由于 swift 是一個(gè)靜態(tài)語(yǔ)言, 所以沒(méi)有 Objective-C 中的消息發(fā)送這些動(dòng)態(tài)機(jī)制, dynamic 的作用就是讓 swift 代碼也能有 Objective-C 中的動(dòng)態(tài)機(jī)制, 常用的地方就是 KVO 了, 如果要監(jiān)控一個(gè)屬性, 則必須要標(biāo)記為 dynamic
typealias
給一個(gè)類(lèi)型取別名,例
public typealias RxTime = Date
用于協(xié)議中定義了泛型時(shí)朝巫,在實(shí)際使用的時(shí)候鸿摇,需要給這個(gè)泛型確定一個(gè)真實(shí)類(lèi)型
associatedtype
簡(jiǎn)單來(lái)說(shuō)就是 protocol 使用的泛型,一般聯(lián)合typealias使用
protocol ListProtcol {
associatedtype Element
func push(_ element:Element)
func pop(_ element:Element) -> Element?
}
實(shí)現(xiàn)協(xié)議的時(shí)候, 可以使用 typealias 指定為特定的類(lèi)型, 也可以自動(dòng)推斷, 如
class IntList: ListProtcol {
typealias Element = Int // 使用 typealias 指定為 Int
var list = [Element]()
func push(_ element: Element) {
self.list.append(element)
}
func pop(_ element: Element) -> Element? {
return self.list.popLast()
}
}
class DoubleList: ListProtcol {
var list = [Double]()
func push(_ element: Double) {// 自動(dòng)推斷
self.list.append(element)
}
func pop(_ element: Double) -> Double? {
return self.list.popLast()
}
}
where
可以限定泛型的類(lèi)
where語(yǔ)句在if中使用時(shí)劈猿,在swift4及以后拙吉,被,代替
extension ListProtcol where Element == Int {
func isInt() ->Bool {
return true
}
}
case
case可在if潮孽、switch語(yǔ)句中使用
//case 不只是在switch中使用
//注意,where語(yǔ)句在if中使用時(shí)筷黔,在swift4及以后往史,被,代替
/*
if 中使用case,where
*/
let tempInt = 23
if case 10...30 = tempInt{
print("if case")
}
if case 10...30 = tempInt, tempInt<25{
print("if case where")
}
if tempInt<30,tempInt>20{
print("if where")
}
/*
switch 中使用where
*/
let pointTemp = (10,20)
switch pointTemp {
case (let x,let y) where x == y/2 :
print ("switch中使用where")
default:
print("default")
}
/*
for in中使用where佛舱、case
*/
for i in 1..<20 where I>10{
print("for in中使用where椎例,i = \(i)")
}
for case let i in 1..<20 where I>10{
print("for in中使用case where,i = \(i)")
}
guard
guard请祖,保證符合條件订歪,否則怎樣(guard關(guān)鍵字,需要return或者throw配合使用肆捕,所以一般必須在函數(shù)體中使用)
func testGuard(x:Int?)->(){
guard let testGuardTemp = x,testGuardTemp>20 else {
print("guard的用法")
return
}
print("guard的用法:",testGuardTemp)
return
}
testGuard(x:nil)
testGuard(x: 23)
//guard與if的區(qū)別刷晋,在于guard中進(jìn)行可選型解包而聲明的變量,能在方法體內(nèi)下繼續(xù)使用慎陵,if則只能在if體內(nèi)使用
guard 和 if 類(lèi)似, 不同的是, guard 總是有一個(gè) else 語(yǔ)句, 如果表達(dá)式是假或者值綁定失敗的時(shí)候, 會(huì)執(zhí)行 else 語(yǔ)句, 且在 else 語(yǔ)句中一定要停止函數(shù)調(diào)用 例如
guard 1 + 1 == 2 else {
fatalError("something wrong")
}
常用使用場(chǎng)景為, 用戶登錄的時(shí)候, 驗(yàn)證用戶是否有輸入用戶名密碼等
guard let userName = self.userNameTextField.text,
let password = self.passwordTextField.text else {
return
}
inout
輸入輸出參數(shù), 如:
func swap( a: inout Int, b: inout Int) {
let temp = a
a = b
b = temp
}
var a = 1
var b = 2
print(a, b)// 1 2
swap(a: &a, b: &b)
print(a, b)// 2 1</pre>
weak眼虱、unowned
兩者都是弱引用,都只能使用在類(lèi)實(shí)例上面
weak修飾的變量荆姆,對(duì)象釋放后自動(dòng)置為nil(因此被標(biāo)記為 @weak
的變量一定需要是 Optional
值)
weak弱引用多用于通常的解決循環(huán)引用問(wèn)題場(chǎng)景蒙幻。
unowned修飾的變量,對(duì)象釋放后不會(huì)自動(dòng)置為nil胆筒,仍然保留釋放對(duì)象的地址邮破,所以可能發(fā)生野指針問(wèn)題
unowned無(wú)主引用用于一個(gè)屬性允許設(shè)置為 nil
,而另一個(gè)屬性不允許設(shè)置為 nil
仆救,并會(huì)造成潛在的強(qiáng)引用循環(huán)的場(chǎng)景抒和。
從安全角度來(lái)說(shuō),weak優(yōu)于unowned彤蔽,但是從性能上說(shuō)摧莽,unowned優(yōu)于weak(weak的實(shí)質(zhì)是對(duì)unowned的封裝,包裹了一個(gè)可選值)
1顿痪、Unowned和Weak的使用時(shí)機(jī)
Unowned一般使用在其所修飾的對(duì)象和所處的block環(huán)境的生命周期一致的時(shí)候镊辕。 簡(jiǎn)單來(lái)說(shuō),Unowned修飾的對(duì)象蚁袭,在整個(gè)block的使用期間都應(yīng)該是有效的征懈,即不可為nil。
Weak則可以使用為block 的生命周期超出其對(duì)象進(jìn)行修飾揩悄。 意思是可以修飾可能變成nil的對(duì)象卖哎。用Swift中的話語(yǔ)來(lái)說(shuō)就是Optional對(duì)象。
相比之下,weak的使用范圍更加廣泛亏娜,如果不考慮性能的話焕窝,我們大可以無(wú)論什么情況都使用weak將會(huì)更加安全。然而它掂,既然Unowned存在溯泣,必將有他的意義 —— 出于性能考慮,我們應(yīng)該在可以使用Unowned的時(shí)候盡可能的使用Unowned发乔,具體原因請(qǐng)往下看雪猪。
2、Unowned 比Weak的開(kāi)銷(xiāo)更小
Swift 中的每個(gè)對(duì)象保持了兩個(gè)引用計(jì)數(shù)器只恨,一個(gè)是強(qiáng)引用計(jì)數(shù)器译仗,用來(lái)決定 ARC 什么時(shí)候可以安全地析構(gòu)這個(gè)對(duì)象纵菌,另外一個(gè)附加的弱引用計(jì)數(shù)器咱圆,用來(lái)計(jì)算創(chuàng)建了多少個(gè)指向這個(gè)對(duì)象的 unowned 或者 weak 引用功氨,當(dāng)這個(gè)計(jì)數(shù)器為零時(shí)捷凄,這個(gè)對(duì)象將被析構(gòu) 跺涤。
弱引用計(jì)數(shù)器在增加之前(這是一個(gè)原子操作)桶错,會(huì)事先檢查一個(gè)對(duì)象的強(qiáng)引用計(jì)數(shù)器的值牛曹,當(dāng)值大于0的時(shí)候,才確保這是有效的超营。不然我們?cè)L問(wèn)一個(gè)無(wú)效的值將會(huì)引起程序運(yùn)行時(shí)報(bào)錯(cuò)從而導(dǎo)致崩潰。
Unowned 在編譯的時(shí)候不跟,進(jìn)行了優(yōu)化窝革,它不會(huì)對(duì)有效只進(jìn)行辨別:如果其引用的對(duì)象是一個(gè)有效值虐译,它將會(huì)順利在弱引用計(jì)數(shù)器原本的基礎(chǔ)之上加1漆诽。如果是一個(gè)無(wú)效的值厢拭,那它將指向一個(gè)垃圾內(nèi)存中的地址供鸠,在運(yùn)行的時(shí)候楞捂,這將會(huì)產(chǎn)生錯(cuò)誤趋厉,這就是為什么我們需要在使用Unowned時(shí)候觅廓,要保證對(duì)象生命周期的有效性杈绸。
Weak針對(duì)Unowned 進(jìn)行了包裝(光憑這一點(diǎn)瞳脓,Unowned 在性能上優(yōu)于Weak)劫侧。Swift 的 weak 引用添加了附加層,間接地把 unowned 引用包裹到了一個(gè)可選容器里面拳球,會(huì)對(duì)可選值進(jìn)行相應(yīng)的處理祝峻,這將帶來(lái)一定的開(kāi)銷(xiāo)莱找。所以盡管我們給一個(gè)nil對(duì)象添加Weak 修飾奥溺,程序運(yùn)行中谚赎,依舊不會(huì)報(bào)錯(cuò)。
這里的性能對(duì)比棕所,驗(yàn)證了上面所說(shuō)的琳省,我們應(yīng)該在對(duì)象的生命周期允許的情況下针贬,盡量使用Unowned 桦他。
_
"_"在swift中有特殊的意義快压,一般使用來(lái)蔫劣,用于占位進(jìn)行忽略.
(1)函數(shù)參數(shù)名忽略脉幢;
(2)10_000(跟10000一樣嫌松,但是加_后更易讀)
mutating :
struct 和 class 的差別是 struct 的 function 要去改變 property 的值的時(shí)候要加上 mutating珊蟀,而 class 不用育灸。
throws 磅崭、 rethrows
throws 用在函數(shù)上, 表示這個(gè)函數(shù)會(huì)拋出錯(cuò)誤. 有兩種情況會(huì)拋出錯(cuò)誤, 一種是直接使用 throw 拋出, 另一種是調(diào)用其他拋出異常的函數(shù)時(shí), 直接使用 try xx 沒(méi)有處理異常. 如
enum DivideError: Error {
case EqualZeroError;
}
func divide(_ a: Double, _ b: Double) throws -> Double {
guard b != Double(0) else {
throw DivideError.EqualZeroError
}
return a / b
}
func split(pieces: Int) throws -> Double {
return try divide(1, Double(pieces))
}
rethrows 與 throws 類(lèi)似, 不過(guò)只適用于參數(shù)中有函數(shù), 且函數(shù)會(huì)拋出異常的情況, rethrows 可以用 throws 替換, 反過(guò)來(lái)不行 如
rethrows -> Double {
return try function(a, b)
}
try砸喻? 割岛、 try癣漆!、try
用于處理可拋出異常的函數(shù)婚肆。
try需要配合do catch
使用。
try两残? 人弓、 try健芭!, 使用這兩個(gè)關(guān)鍵字可以不用寫(xiě) do catch
.
區(qū)別在于, try? 在用于處理可拋出異常函數(shù)時(shí), 如果函數(shù)拋出異常, 則返回 nil, 否則返回函數(shù)返回值的可選值, 如:
print(try? divide(2, 1))
// Optional(2.0)
print(try? divide(2, 0))
// nil
而 try! 則在函數(shù)拋出異常的時(shí)候崩潰, 否則則返會(huì)函數(shù)返回值, 相當(dāng)于(try? xxx)!, 如:
print(try! divide(2, 1))
// 2.0
print(try! divide(2, 0))
// 崩潰
訪問(wèn)控制相關(guān)關(guān)鍵字(public等)
open > public > internal > fileprivate > private
open:在其他模塊(命名空間)內(nèi)使用可被訪問(wèn)谴麦、繼承、重寫(xiě)
public:在其他模塊內(nèi)只能被訪問(wèn)闯袒,不能被繼承
internal:僅在自身模塊中能訪問(wèn)晌区、繼承昌罩、重寫(xiě)
fileprivate:當(dāng)前文件內(nèi)訪問(wèn)
private: 當(dāng)前作用域內(nèi)訪問(wèn)