Swift 學(xué)習(xí)2

一:playground

作用:學(xué)習(xí)代碼、實(shí)驗(yàn)代碼、測試代碼

官方的學(xué)習(xí)資源是以playgroud形式提供的,建立自己的playgroud文件,能夠每次版本升級時(shí),第一時(shí)間發(fā)現(xiàn)語法的變化

Swift程序中與Oc的不同

1、沒有.h與.m文件,都是以.swift結(jié)尾的文件

2、沒有main.m文件 —— appDelegate中的@UIApplicationMain 就是程序的入口

3、Swift的類都是用class標(biāo)識

4、OC中的initwithXX方法在Swift中是“類型(xxx)”

5、swift中的屬性和方法都是用 “.” 的形式

6、結(jié)尾可以不加分號(加了也可以)

7、在當(dāng)前類中使用當(dāng)前屬性,不需要加“self."(除了閉包)

8、在swift中把枚舉分成了兩部分"枚舉名.枚舉值",枚舉名可以省略

9、在swift中使用print打印,也可以使用nslog,但效率沒有print高


二、Swift的基本語法

1、變量與常量

swift中變量與常量的類型可以不設(shè)置,在賦值時(shí)由系統(tǒng)自動(dòng)推斷,如果希望手動(dòng)指定那么在變量或常量后加":類型"

在swift中,不同類型之間不能進(jìn)行運(yùn)算,oc可以,因?yàn)閛c有隱式轉(zhuǎn)換

運(yùn)算符對稱,運(yùn)算符左右兩邊的空格要對稱,如果一邊有空格,另一邊沒有就會(huì)報(bào)錯(cuò),一邊多了個(gè)空格不會(huì)報(bào)錯(cuò),但影響美觀

var來聲明變量。在swift中,如果定義了一個(gè)變量,沒有初始值的時(shí)候,系統(tǒng)會(huì)報(bào)錯(cuò)。如果開發(fā)者就是想聲明一個(gè)變量為空,那么需要在類型的后面加個(gè)"?"

let用來聲明常量。在swift中,如果定義了一個(gè)常量,沒有初始值的時(shí)候,系統(tǒng)會(huì)報(bào)錯(cuò)。對于常量,不能通過后面加"?"來處理,只能賦值為nil或者0來處理。


2、if判斷與guard判斷

在swift中沒有 ?非零即真 ?的概念,條件語句一定是bool類型(true/false )

swift中條件語句的小括號可以省略,但如果執(zhí)行代碼只有一句,代碼塊的大括號不可以省略

guard判斷如果條件不成立,那么執(zhí)行else代碼塊,相當(dāng)于一個(gè)沒有第一個(gè)代碼塊的if


3、三目運(yùn)算 與 可選類型

三目運(yùn)算在swift中與oc沒有區(qū)別

在可選類型中,"??" 是一個(gè)簡單的三目運(yùn)算,比如

age ?? 0 ? 意為age為nil或空時(shí)使用??后面的0值

使用 ? 修飾的類型為可選類型,屬性在賦值時(shí)候,會(huì)帶有Optional關(guān)鍵字,這樣不能與不帶關(guān)鍵字的類型做操作,可以使用 "!"來強(qiáng)行解包,但使用需要小心小心再小心。


4、if ?_ let ?/ ? guard ? ?_ ?let ??

類似自定義view的if(self = ?[super ? XXX])中的 ?“=”,判斷等號前面的有值就執(zhí)行第一代碼塊,否則else。聲明的作用域僅僅在if內(nèi)部。

而guard是判斷不成立則執(zhí)行else,聲明作用域?yàn)間uard的下方(不僅僅在guard內(nèi)部)


5、for循環(huán)

不可以使用c形式的for循環(huán),++形式在swift3.0后移除不能在使用,for循環(huán)的時(shí)候,小括號不要寫

語法:

for ? ?i ? ? ? in ? ? ? ?x..<y ? ?(x ---- y-1)

for ? ?i ? ? ? ?in ? ? ? x...y ? ? ? (x-------y)

for ? ?value ? in ?arr ? ? ? ? ? ?(arr 數(shù)組)


6、switch

swift的switch可以判斷任何類型,比oc要廣;

默認(rèn)沒有break,并且不會(huì)造成穿透效果(如果想實(shí)現(xiàn)穿透,設(shè)置關(guān)鍵字 "fallthrough");

switch可以進(jìn)行范圍判斷 ? ? ? ? ? 語法:

case ? ? _where ? c(聲明的變量) > 60 (范圍)


7、字符串的長度、遍歷、截取、拼接

在swift中字符串可以直接使用String表示,string本質(zhì)是一個(gè)結(jié)構(gòu)體,比oc的NSSting更加輕便,而且效率更高。

問題:

——如何獲取字符串長度

? ? ?——str.characters.count

——如何遍歷字符串

? ? ?——for char ? in ?str.characters ? 其中char就是一個(gè)字符

——字符串字節(jié)注意點(diǎn)

? ? ——一個(gè)英文/數(shù)字等于一個(gè)字節(jié),一個(gè)中文等于三個(gè)字節(jié)

——字符串截取

? ? ?——如一字符串"123456789"

? ? ? ? ~? 最后兩個(gè)不要? let? end2index = str.index(str.endIndex, offsetBy: - 2)

? ? ? ? ? ?str.substring(to: end2index)

? ? ? ? ~ ?前兩個(gè)不要? let? start2index = str.index(str.start, offsetBy: 2)

? ? ? ? str.substring(from: end2index)

? ? ? ? ~? 如何把string轉(zhuǎn)化成NSString

? ? ? ? 使用as 相當(dāng)于強(qiáng)轉(zhuǎn)

——字符串如何拼接

? ? ——需求:兩個(gè)常量 "老王" ?18,拼接成"我叫老王今年18"

? ? ? ? ?~方式1

? ? ? ? ? ?~ ?"我叫" + name + "今年" + string(age)

? ? ? ?~方式2

? ? ? ? ? ? ~"我叫\(zhòng)(name)今年\(age)" ? ?**常用


8、數(shù)組定義、拼接、遍歷

——數(shù)組定義

——使用中括號形式,如果數(shù)組中有不同類型,需指定一下 ":[Any]"

——如何定義可變和不可變的數(shù)組

——可變數(shù)組用var ? ?不可變的就是let

——如何合并數(shù)組

——"+=" ?arr ?+= ?arrb;

——如何往數(shù)組添加元素

——"append"

——如何移除元素

——"remove"系列

——如何獲取元素

——和oc一樣通過下標(biāo)


9、函數(shù)

無參無返、有參無返,有參有返、外部參數(shù)

無返回值的三種寫法

方法一

func ?demo (){

}

方法二

func ?demo () -> Void{

}

方法三

func ?demo () -> (){

}

——函數(shù)類型作為參數(shù)

你可以用(Int, Int) -> Int這樣的函數(shù)類型作為另一個(gè)函數(shù)的參數(shù)類型。這樣你可以將函數(shù)的一部分實(shí)現(xiàn)留給函數(shù)的調(diào)用者來提供。

下面是另一個(gè)例子,正如上面的函數(shù)一樣,同樣是輸出某種數(shù)學(xué)運(yùn)算結(jié)果:

func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {

print("Result: \(mathFunction(a, b))")

}

printMathResult(addTwoInts, 3, 5)

// 打印 "Result: 8"

——函數(shù)類型作為返回類型

你可以用函數(shù)類型作為另一個(gè)函數(shù)的返回類型。你需要做的是在返回箭頭(->)后寫一個(gè)完整的函數(shù)類型。

下面的這個(gè)例子中定義了兩個(gè)簡單函數(shù),這兩個(gè)函數(shù)的類型都是(Int) -> Int:

func stepForward(_ input: Int) -> Int {

return input + 1

}

func stepBackward(_ input: Int) -> Int {

return input - 1

}

如下名為chooseStepFunction(backward:)的函數(shù),它的返回類型是(Int) -> Int類型的函數(shù)。

func chooseStepFunction(backward: Bool) -> (Int) -> Int {

return backward ? stepBackward : stepForward

}

——函數(shù)內(nèi)部定義函數(shù)(嵌套函數(shù))

默認(rèn)情況下,嵌套函數(shù)是對外界不可見的,但是可以被它們的外圍函數(shù)(enclosing function)調(diào)用。一個(gè)外圍函數(shù)也可以返回它的某一個(gè)嵌套函數(shù),使得這個(gè)函數(shù)可以在其他域中被使用。

func chooseStepFunction(backward: Bool) -> (Int) -> Int {

? ? ? ? ? ?func stepForward(input: Int) -> Int { return input + 1 }

? ? ? ? ? ? func stepBackward(input: Int) -> Int { return input - 1 }

? ? ? ? ? ? return backward ? stepBackward : stepForward

}

var currentValue = -4

let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)

// moveNearerToZero now refers to the nested stepForward() function

while currentValue != 0 {

? ? ? ? ? ?print("\(currentValue)... ")

? ? ? ? ? ?currentValue = moveNearerToZero(currentValue)

}

print("zero!")

// -4...

// -3...

// -2...

// -1...

// zero!


10、block 閉包

——基本的閉包形式

block一般用在 ?異步任務(wù)完成的回調(diào)

無參無返回

方法一

let ? demo ?= {

}

方法二

let? demo? = { () in

}

方法三

let? demo? = { () ->Void ?in

}

方法四

let? demo? = { () -> () in

}

有參數(shù)無返回

let ?demo = ?{ (a: Int, b:Int) in

}

有參數(shù)有返回

let ?demo = ?{ (a: Int, b:Int) ?-> Int in

}

解析:in后面寫具體希望執(zhí)行的代碼,in前面為 ?有參無返/有參有返 ?的定義

——尾隨閉包

——若將閉包作為函數(shù)最后一個(gè)參數(shù),可以省略參數(shù)標(biāo)簽,然后將閉包表達(dá)式寫在函數(shù)調(diào)用括號后面

func testFunction(testBlock: ()->Void){

//這里需要傳進(jìn)來的閉包類型是無參數(shù)和無返回值的

testBlock()

}

//正常寫法

testFunction(testBlock:?{

print("正常寫法")

})

單表達(dá)式閉包隱式返回

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } )

根據(jù)上下文推斷類型

reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

單行表達(dá)式閉包可以通過省略return關(guān)鍵字來隱式返回單行表達(dá)式的結(jié)果,如上版本的例子可以改寫為:

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

在這個(gè)例子中,sorted(by:)方法的參數(shù)類型明確了閉包必須返回一個(gè)Bool類型值。因?yàn)殚]包函數(shù)體只包含了一個(gè)單一表達(dá)式(s1 > s2),該表達(dá)式返回Bool類型值,因此這里沒有歧義,return關(guān)鍵字可以省略。

1、如果有多個(gè)參數(shù),最后一個(gè)參數(shù)為閉包,(這是才稱為尾隨閉包)那么尾隨閉包就會(huì)提前把小括號關(guān)閉

//尾隨閉包寫法

testFunction(){

print("尾隨閉包寫法")

}

2、當(dāng)只有一個(gè)參數(shù)且為閉包時(shí),那么尾隨閉包就會(huì)把小括號和參數(shù)省略

//也可以把括號去掉,也是尾隨閉包寫法。推薦寫法

testFunction?{

print("去掉括號的尾隨閉包寫法")

}

——逃逸閉包

當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中,需要這個(gè)閉包在函數(shù)返回之后才被執(zhí)行,我們就稱該閉包從函數(shù)種逃逸。一般如果閉包在函數(shù)體內(nèi)涉及到異步操作,但函數(shù)卻是很快就會(huì)執(zhí)行完畢并返回的,閉包必須要逃逸掉,以便異步操作的回調(diào)。

逃逸閉包一般用于異步函數(shù)的回調(diào),比如網(wǎng)絡(luò)請求成功的回調(diào)和失敗的回調(diào)。語法:在函數(shù)的閉包行參前加關(guān)鍵字“@escaping”。

//例1

func?doSomething(some:?@escaping?()?->?Void){

//延時(shí)操作,注意這里的單位是秒

DispatchQueue.main.asyncAfter(deadline:?DispatchTime.now()?+?1)?{

//1秒后操作

some()

}

print("函數(shù)體")

}

doSomething?{

print("逃逸閉包")

}

//例2

varcomletionHandle:?()->String?=?{"約嗎?"}

func?doSomething2(some:?@escaping?()->String){

comletionHandle?=?some

}

doSomething2?{

return"叔叔,我們不約"

}

print(comletionHandle())

//將一個(gè)閉包標(biāo)記為@escaping意味著你必須在閉包中顯式的引用self。

//其實(shí)@escaping和self都是在提醒你,這是一個(gè)逃逸閉包,

//別誤操作導(dǎo)致了循環(huán)引用!而非逃逸包可以隱式引用self。

——閉包的循環(huán)引用及解決方法

? ? ? ——原因

? ? ? ? ——原理跟OC中的block類似, 當(dāng)有個(gè)屬性記錄下了函數(shù)傳遞回來的閉包, 產(chǎn)生強(qiáng)引用, 就會(huì)發(fā)生閉包的循環(huán)引用?

? ? ? ? ——解決方法(三種)

? ? ? ? ? ——使用weak修飾變量, 打破強(qiáng)引用, 因?yàn)槭褂脀eak修飾的變量有一次變成nil的機(jī)會(huì)

? ? ? ? ? ——使用[weak self] 修飾閉包原理跟__weak類似, 這樣在閉包中使用self, 就是弱引用

? ? ? ? ?——使用[unowned self ] 修飾閉包, 跟__unsafe_unretained類似, 不安全

11、面向?qū)ο?/h1>

在一個(gè)模型類中,屬性用var而不是let。

創(chuàng)建Person對象時(shí),可以直接使用 ? ?"類名()"的形式

聲明常量或者變量時(shí)候,默認(rèn)應(yīng)該是有值的。

? ? ? ? ? 解決方案

? ? ? ? ? ?方法一

? ? ? ? ? 把屬性變?yōu)榭蛇x類型(一般使用這種)

? ? ? ? ? 方法二

? ? ? ? ? 直接賦值

? ? ? ? ?方法三

? ? ? ? 在構(gòu)造函數(shù)中賦值,(需要寫在super之前)

——重寫與重載構(gòu)造函數(shù)

? ? ——重寫

? ? ?父類方法,子類再寫一遍

? ? ——重載

? ? ?都是在一個(gè)類中,方法名相同,參數(shù)不同

? ? ?好處:更靈活,方便記憶,只需要記住方法名即可


12、異常處理

所有的方法后帶有throws的都應(yīng)該進(jìn)行錯(cuò)誤處理

寫法為 ? ? 在所需執(zhí)行的代碼前面寫 ? ? ?"try/try?/try!" ? (其中try與try?比較常用)

方式1 ? try

使用默認(rèn)的try時(shí),如果有錯(cuò)誤可以通過do—catch進(jìn)行捕捉,如果沒有錯(cuò)誤,那就正常執(zhí)行

do{

? ? ? ?let ? res = try ? JSONSerialization.jsonObject(with:data,options:[])

? ? ? ?print()

}catch{

? ? ? print()

}

方式2? try?

try?如果使用的是可選try,那么如果有錯(cuò)誤會(huì)返回nil,沒有錯(cuò)誤就會(huì)正常執(zhí)行

let? res = try? JSONSerialization.jsonObject(with:data,options:[])

print()

方式3? try!

try!是強(qiáng)行try,意思是可以放心的用,但是如果是錯(cuò)誤的,那么就崩潰了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容