一:playground
作用:學(xué)習(xí)代碼、實(shí)驗(yàn)代碼、測(cè)試代碼
官方的學(xué)習(xí)資源是以playgroud形式提供的,建立自己的playgroud文件,能夠每次版本升級(jí)時(shí),第一時(shí)間發(fā)現(xiàn)語法的變化
Swift程序中與Oc的不同
1、沒有.h與.m文件,都是以.swift結(jié)尾的文件
2、沒有main.m文件 —— appDelegate中的@UIApplicationMain 就是程序的入口
3、Swift的類都是用class標(biāo)識(shí)
4、OC中的initwithXX方法在Swift中是“類型(xxx)”
5、swift中的屬性和方法都是用 “.” 的形式
6、結(jié)尾可以不加分號(hào)(加了也可以)
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)算符對(duì)稱,運(yùn)算符左右兩邊的空格要對(duì)稱,如果一邊有空格,另一邊沒有就會(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ò)。對(duì)于常量,不能通過后面加"?"來處理,只能賦值為nil或者0來處理。
2、if判斷與guard判斷
在swift中沒有 ?非零即真 ?的概念,條件語句一定是bool類型(true/false )
swift中條件語句的小括號(hào)可以省略,但如果執(zhí)行代碼只有一句,代碼塊的大括號(hào)不可以省略
guard判斷如果條件不成立,那么執(zhí)行else代碼塊,相當(dāng)于一個(gè)沒有第一個(gè)代碼塊的if
3、三目運(yùn)算 與 可選類型
三目運(yùn)算在swift中與oc沒有區(qū)別
在可選類型中,"??" 是一個(gè)簡(jiǎn)單的三目運(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])中的 ?“=”,判斷等號(hào)前面的有值就執(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í)候,小括號(hào)不要寫
語法:
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、字符串的長(zhǎng)度、遍歷、截取、拼接
在swift中字符串可以直接使用String表示,string本質(zhì)是一個(gè)結(jié)構(gòu)體,比oc的NSSting更加輕便,而且效率更高。
問題:
——如何獲取字符串長(zhǎng)度
? ? ?——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ù)組定義
——使用中括號(hào)形式,如果數(shù)組中有不同類型,需指定一下 ":[Any]"
——如何定義可變和不可變的數(shù)組
——可變數(shù)組用var ? ?不可變的就是let
——如何合并數(shù)組
——"+=" ?arr ?+= ?arrb;
——如何往數(shù)組添加元素
——"append"
——如何移除元素
——"remove"系列
——如何獲取元素
——和oc一樣通過下標(biāo)
9、函數(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è)簡(jiǎn)單函數(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ù)是對(duì)外界不可見的,但是可以被它們的外圍函數(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)用括號(hà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ì)提前把小括號(hào)關(guān)閉
//尾隨閉包寫法
testFunction(){
print("尾隨閉包寫法")
}
2、當(dāng)只有一個(gè)參數(shù)且為閉包時(shí),那么尾隨閉包就會(huì)把小括號(hào)和參數(shù)省略
//也可以把括號(hào)去掉,也是尾隨閉包寫法。推薦寫法
testFunction?{
print("去掉括號(hào)的尾隨閉包寫法")
}
——逃逸閉包
當(dāng)一個(gè)閉包作為參數(shù)傳到一個(gè)函數(shù)中,需要這個(gè)閉包在函數(shù)返回之后才被執(zhí)行,我們就稱該閉包從函數(shù)種逃逸。一般如果閉包在函數(shù)體內(nèi)涉及到異步操作,但函數(shù)卻是很快就會(huì)執(zhí)行完畢并返回的,閉包必須要逃逸掉,以便異步操作的回調(diào)。
逃逸閉包一般用于異步函數(shù)的回調(diào),比如網(wǎng)絡(luò)請(qǐng)求成功的回調(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對(duì)象時(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ò)誤的,那么就崩潰了