即將入職新公司梯刚,換工作的間歇期有時(shí)間看一看知識(shí)點(diǎn),新項(xiàng)目里swift和oc混編薪寓,所以趁著機(jī)會(huì)看了下swift語法亡资,由于UIKit oc和swift一樣,所以只進(jìn)行swift語法的學(xué)習(xí)向叉,翻了一遍《swift 4從零到精通iOS開發(fā)》锥腻,第一遍閱讀用筆標(biāo)出了語法不同點(diǎn),然后邊寫代碼實(shí)驗(yàn)邊做筆記的形式記錄母谎。
一瘦黑、基本數(shù)據(jù)類型
1.元組
//元組允許一些不相關(guān)的類型進(jìn)行自由組合,成為新的集合類型奇唤,適用于簡單數(shù)據(jù)結(jié)構(gòu)幸斥,復(fù)雜數(shù)據(jù)結(jié)構(gòu)依然推薦用類或結(jié)構(gòu)體。
var? pen:(name:String, length:NSInteger) = ("我的鋼筆", 15)
//訪問屬性
print("名字:"+pen.name+" 長度:\(pen.length)”)
2.可選值類型
swift中基本數(shù)據(jù)類型不能為nil咬扇,如果想可以為nil需要用?進(jìn)行包裝成可選值類型甲葬,用該值時(shí)需要用!進(jìn)行拆包操作。
?!是打包和拆包
舉例:
? ? //編譯報(bào)錯(cuò)懈贺,'nil' cannot be assigned to type 'String'
? ? var str:String = "hello"
? ? str =nil
? ? //編譯報(bào)錯(cuò)演顾,Variable 'str1' used before being initialized,因?yàn)閟wift中String是普通類型供搀,普通類型不能等于nil
? ? var str1:String
? ? if str1==nil {
? ? }
?/*
?? ? 編譯通過,str2是String?類型
?? ? swift里在普通類型后面加钠至?可以把普通類型包裝成Optional類型葛虐。Optional類型不會(huì)單獨(dú)存在,總會(huì)附著于某個(gè)具體數(shù)據(jù)類型之上棉钧,具體數(shù)據(jù)類型可以是基本數(shù)據(jù)類型屿脐、結(jié)構(gòu)體或者類等。
?? ? Optional類型只有兩種值:
?? ? 1.如果附著類型對應(yīng)的量值有具體的值宪卿,則為具體值得包裝的诵。
?? ? 2.如果附著類型對應(yīng)的量值沒有具體的值,則其為nil
? ? */
? ? var str2:String?
? ? if str2==nil {
? ? ? ? print("str2為空")
? ? }
輸出str2為空
? ? //編譯報(bào)錯(cuò)佑钾,Value of optional type 'String?' must be unwrapped to a value of type 'String'
? ? //如果使用str2必須進(jìn)行拆包
? ? var str3 = "hello" + str2
? ? print(str3)
?可以出現(xiàn)在類型后面和實(shí)例后面西疤,如果出現(xiàn)在類型后面,代表此類型對應(yīng)的Optional類型休溶,如果出現(xiàn)在實(shí)例后面則代表可選鏈的調(diào)用代赁。*暫時(shí)沒弄懂
!也可以出現(xiàn)在類型后面和實(shí)力后面,出現(xiàn)在類型后面代表一種隱式解析的語法結(jié)構(gòu)兽掰。*暫時(shí)沒弄懂
? ? //運(yùn)行報(bào)錯(cuò)芭碍,F(xiàn)atal error: Unexpectedly found nil while unwrapping an Optional value: file
? ? //不能對nil拆包,所以拆包之前需要判斷是否為空
var str2:String?
? ? var str3 = "hello" + str2!
? ? print(str3)
? ? //不會(huì)走進(jìn)判斷條件里面
? ? var str2:String?
? ? if str2 != nil {
? ? ? ? var str3 = "hello" + str2!
? ? ? ? print(str3)
? ? }
? ? //用if let結(jié)構(gòu)判斷要拆包的變量是否為nil
? ? if let tmp = str2 {
? ? ? ? var str3 = "hello" + str2!
? ? ? ? print(str3)
? ? }else{
? ? ? ? str2 ="world"
? ? ? ? var str3 = " hello" + str2!
? ? ? ? print(str3)
? ? }
? ? //typealias關(guān)鍵字可以為類型取別名
? ? typealias Price = NSInteger
? ? var price:Price = 12;
二孽尽、字符串與集合
+和\()結(jié)構(gòu)
? ? var str1 = "hello"
? ? var str2 = "world"
? ? var str3 = str1 + " " + str2
? ? print(str3)//打印hello world “+”操作符可以實(shí)現(xiàn)字符串拼接
? ? var str4 = "hello \(str2)"
? ? print(str4)//打印hello world 如果str2未定義會(huì)報(bào)錯(cuò)窖壕,
2.isEmpty方法
? ? //打印空字符串 ""認(rèn)為是空字符串
? ? var str5 = ""
? ? if str5.isEmpty {
? ? ? ? print("空字符串")
? ? }else{
? ? ? ? print(str5)
? ? }
? ? //編譯報(bào)錯(cuò),Value of optional type 'String?' must be unwrapped to refer to member 'isEmpty' of wrapped base type 'String'
? ? var str5:String?
? ? if str5.isEmpty {
? ? ? ? print("空字符串")
? ? }else{
? ? ? ? print(str5)
? ? }
? ? //打印str3 str4相等 = < >可以進(jìn)行字符串判斷
? ? if str3 == str4 {
? ? ? ? print("str3 str4相等")
? ? }
3.數(shù)組
Array有別于NSArray
? ? //以下兩種寫法一樣杉女,都是聲明一個(gè)NSInteger數(shù)組
? ? var array1:[NSInteger] = [0,1,2,3,4,5]
? ? var array2:Array<NSInteger> = [0,1,2,3,4,5]
? ? //數(shù)組判空
? ? if array1.isEmpty {
? ? ? ? print("空數(shù)組")
? ? }
? ? //訪問數(shù)組元素
? ? var a = array1[1]
? ? var subArray = array1[0 ... 3]
? ? //訪問第一個(gè)元素
? ? var b = array1.first
? ? //訪問最后一個(gè)元素
? ? var c = array2.last
? ? array1[2] = 15;
? ? var array3:NSArray = [NSArray (array: array1)]
? ? //array3[2] = 3;編譯會(huì)報(bào)錯(cuò)瞻讽,Array有別于NSArray
? ? var array4:NSMutableArray = [NSMutableArray (array: array1)]
? ? array4.firstObject
//Array取第一個(gè)元素是.first NSMutableArray取第一個(gè)元素是.firstObject
? ? array1.insert(20, at: 0)
? ? array1.remove(at: 3)
? ? array1.removeFirst()
? ? array1.removeLast()
? ? array1.removeAll()
4.set類型
Set類型可以實(shí)現(xiàn)去重,同樣有別于NSSet熏挎,NSMutableSet卸夕。
可以取兩個(gè)set的交集、并集婆瓜、補(bǔ)集等
? ? var set:Set<NSInteger> = Set.init()
? ? set.insert(1);
? ? set.insert(3);
? ? set.insert(3);
? ? print(set)//[3, 1]
5.Dictionary類型? ?
//下面兩種聲明方式等價(jià)快集,都表示聲明一個(gè)key為String類型,value為NSInteger類型的字典
? ? //Dictionary也不等價(jià)于NSDictionary NSMutableDictionary
? ? var dic1:[String:NSInteger]
? ? var dic:Dictionary<String, NSInteger> = Dictionary.init()
? ? dic["tom"] = 1
? ? dic["lucy"] = 2
? ? dic["kate"] = 3
? ? var dic2:NSDictionary = NSDictionary.init(dictionary: dic)
? ? var dic3:NSMutableDictionary = NSMutableDictionary.init(dictionary: dic)
? ? dic3.setValue(6, forKey: "lily")
? ? dic3.removeObject(forKey: "tom")
? ? print(dic3)
三廉白、運(yùn)算符與控制流程
合并運(yùn)算符??
合并運(yùn)算符??是一個(gè)二元運(yùn)算符个初,需要兩個(gè)操作數(shù),第一個(gè)操作數(shù)必須為一個(gè)optional值猴蹂,如果此optional值不為nil院溺,則將其進(jìn)行拆包操作,并作為空合并運(yùn)算的運(yùn)算結(jié)果磅轻。
? ? //打印"字符串"珍逸,因?yàn)閟tr有值逐虚,所以對str拆包
? ? var str:String? = "字符串"
? ? var str1 = str ?? "啦啦啦"
? ? print(str1)
區(qū)間運(yùn)算符
? ? /*輸出
? ? true
? ? false
? ? 1
? ? 2
? ? 3*/
? ? let range1 = 1...3
? ? let range2 = 1..<3
? ? print(range1 ~= 3)
? ? print(range2 ~= 3)
? ? for index in range1 {
? ? ? ? print(index)
? ? }
for-in循環(huán)結(jié)構(gòu)
swift刪除了for(int i; i<5; i++)這種for循環(huán)結(jié)構(gòu),只有for-in谆膳。也刪除了++叭爱, —運(yùn)算符。
for循環(huán)接收兩個(gè)參數(shù)漱病,第二個(gè)參數(shù)可以是一個(gè)集合類型的實(shí)例也可以是范圍區(qū)間买雾,第一個(gè)參數(shù)為捕獲參數(shù),每次從第二個(gè)參數(shù)中遍歷出的元素會(huì)賦值給它杨帽,可供開發(fā)者在循環(huán)結(jié)構(gòu)中直接使用漓穿。
? ? let range1 = 1...3
? ? for index in range1 {
? ? ? ? print(index)
? ? }
//輸出123
? ? let array:Array = [0,1,2]
? ? for value in array {
? ? ? ? print(value)
? ? }//輸出012
repeat-while
repeat-whiled會(huì)先執(zhí)行一次循環(huán)體再進(jìn)行條件判斷,類似do while
? ? var i:NSInteger = 0
? ? while i<3 {
? ? ? ? print(i)
? ? ? ? i+=1
? ? }//輸出012
? ? var j:NSInteger = 3
? ? repeat{
? ? ? ? print(j)
? ? ? ? j+=1
? ? }while j<3
? ? //輸出3
if-else
if關(guān)鍵字后面跟的條件必須為嚴(yán)格意義上的邏輯值或者結(jié)果為邏輯值的表達(dá)值
var i:NSInteger = 0
?if i {
? ? ? ? print(i)
? ? }//編譯報(bào)錯(cuò)Cannot convert value of type 'NSInteger' (aka 'Int') to expected condition type ‘Bool’
? ? var i:NSInteger = 0
? ? if i != 0 {
? ? ? ? print(i)
? ? }//編譯不報(bào)錯(cuò)注盈,但是記住!=需要跟i中間有個(gè)空格晃危,否則被認(rèn)為是拆包操作編譯報(bào)錯(cuò)
switch-case
swift中的switch不像oc中只能進(jìn)行int類型的值匹配,swift中的switch可以進(jìn)行任意數(shù)據(jù)類型的匹配老客,case子句的語法和擴(kuò)展更加靈活僚饭。
oc中case語句不會(huì)因?yàn)槠ヅ涑晒Χ袛啵绻籦reak沿量,case的語句會(huì)依次執(zhí)行,swift一個(gè)case語句匹配成功后會(huì)自動(dòng)跳出switch結(jié)構(gòu)冤荆,如果不加特殊處理朴则,switch每個(gè)分支只會(huì)執(zhí)行一次或者不執(zhí)行。
case中的值有三種匹配方式:完全匹配钓简、選擇匹配乌妒、范圍匹配
?? ? ? ? //case的寫法更靈活
? ? let charac:Character = "a"
? ? switch charac {
? ? case "a","b":
? ? ? ? print("charac is a||b")
? ? case "c":
? ? ? ? print("charac is c")
? ? case "d":
? ? ? ? print("charac is d")
? ? default:
? ? ? ? print("no charac")
? ? }
? ? //輸出charac is a||b
//case的寫法
? ? var value:NSInteger = 3
? ? switch value {
? ? case 1...3:
? ? ? ? print("value <= 3")
? ? case 4...6:
? ? ? ? print("value >=4 <=6")
? ? default:
? ? ? ? print("value > 6")
? ? }//輸出value <= 3
//三種匹配方式
? ? var tuple = (4,1)
? ? switch tuple {
? ? case (0,1)://完全匹配:兩個(gè)值都匹配上才算匹配上
? ? ? ? print("完全匹配")
? ? case (_,1)://選擇匹配:忽略某個(gè)值,只進(jìn)行另一個(gè)值的匹配
? ? ? ? print("選擇匹配")
? ? case (0…3,0...3)://范圍匹配:值符合范圍就算匹配上
? ? ? ? print("范圍匹配")
? ? default:
? ? ? ? print("no")
? ? }//輸出 范圍匹配
? //case中捕獲變量
? ? var value2 = (0,0)
? ? switch value2 {
? ? case (let a, 1)://如果第二個(gè)元素為1外邓,則會(huì)走進(jìn)這個(gè)case撤蚊,并且把第一個(gè)值捕獲到a中
? ? ? ? print(a)
? ? case (let b, 0):
? ? ? ? print(b)
? ? case (let a, let b)://捕獲到元組中兩個(gè)元素,等價(jià)于這種寫法let(a,b)
? ? ? ? print(a, b)
? ? default:
? ? ? ? print("")
? ? }
fallthrough
如果需要case中結(jié)構(gòu)執(zhí)行完之后不自動(dòng)進(jìn)行中斷损话,用fallthrough會(huì)繼續(xù)向下執(zhí)行
? ? var tuple = (0,1)
? ? switch tuple {
? ? case (0,1)://兩個(gè)值都匹配上才算匹配上
? ? ? ? print("完全匹配")
? ? ? ? fallthrough
? ? case (_,1)://忽略某個(gè)值侦啸,只進(jìn)行另一個(gè)值的匹配
? ? ? ? print("選擇匹配")
? ? ? ? fallthrough
? ? case (0...3,0...3)://值符合范圍就算匹配上
? ? ? ? print("范圍匹配")
? ? default:
? ? ? ? print("no")
? ? }
? ? //輸出 完全匹配 選擇匹配 范圍匹配
Guard-else
? ? var value3:NSInteger = 3
? ? guard value3 < 4 else {
? ? ? ? print("value3 < 4")
? ? }
? ? print("value3 >= 4")
? ? //打印value3 >= 4
四、函數(shù)
函數(shù)的定義
關(guān)鍵字func聲明函數(shù)丧枪,后面加上參數(shù)列表光涂,->后面加上返回值,沒有返回值可以省略拧烦。
參數(shù)名可以指定名字和類型忘闻,無參函數(shù)傳空即可。
func funName(<#parameters#>) -> <#return type#> {
? ? <#function body#>
}
—————————————————————————————————————————————————————————
返回多個(gè)值可以返回元組恋博。
func getPerson() -> (name:String, age:NSInteger) {
? ? return ("張三", 20);
}
func testFunAndBlock(){
? ? let person = getPerson()
? ? print(person)
}//打印(name: "張三", age: 20)
—————————————————————————————————————————————————————————
可以為參數(shù)取別名齐佳,函數(shù)內(nèi)部用str私恬、value
func setPerson(name str:String, age value:NSInteger){
? ? print("\(str),\(value)")
}
func testFunAndBlock(){
//調(diào)用者調(diào)用外部名字
? ? setPerson(name: "張三", age: 20)
}//打印 張三,20
—————————————————————————————————————————————————————————
函數(shù)參數(shù)支持默認(rèn)值,如果參數(shù)設(shè)置了默認(rèn)值炼吴,可以傳可以不傳此參數(shù)本鸣,傳的話用傳的值,沒傳則用默認(rèn)值缺厉。
func add(value1:NSInteger, value2:NSInteger, value3:NSInteger = 10){
? ? print(value1+value2+value3)
}
func testFunAndBlock(){
? ? add(value1: 1, value2: 2)
? ? add(value1: 1, value2: 2, value3: 3)
}//打印 13 6
—————————————————————————————————————————————————————————
某個(gè)參數(shù)后面加上… 就會(huì)在此參數(shù)設(shè)置為數(shù)量可變永高,傳遞的類型必須相同,可以傳多組可變的參數(shù)
func add2(values:NSInteger...){
? ? var sum:NSInteger = 0
? ? for value in values {
? ? ? ? sum+= value
? ? }
? ? print(sum)
}
func testFunAndBlock(){
? ? add2(values: 1,2,3)
}//打印 6
—————————————————————————————————————————————————————————
swift函數(shù)如果傳遞值類型的蠶食提针,在傳遞過程中會(huì)復(fù)制一份常量命爬,且在函數(shù)內(nèi)不可修改,
func fun(value:NSInteger){
? ? value +=1
}//編譯報(bào)錯(cuò):Left side of mutating operator isn't mutable: 'value' is a 'let' constant
—————————————————————————————————————————————————————————
inout關(guān)鍵字可以再函數(shù)內(nèi)修改傳遞參數(shù)真正的值辐脖,如下所示饲宛,聲明為inout類型的參數(shù)傳遞參數(shù)時(shí)需要使用&
func fun(value:inout NSInteger){
? ? value+= 1
}
func testFunAndBlock(){
? ? var param = 10
? ? fun(value: ¶m)
? ? print(param)
}//打印 11
函數(shù)嵌套
swift支持函數(shù)嵌套,在函數(shù)內(nèi)部再創(chuàng)建函數(shù)嗜价,子函數(shù)只能在父函數(shù)內(nèi)部調(diào)用艇抠,不能被其他函數(shù)調(diào)用。但可以作為返回值傳遞到父函數(shù)外部久锥。
func fun2(value:NSInteger, value2:NSInteger){
? ? func add(val1:NSInteger, val2:NSInteger)->NSInteger{
? ? ? ? return val1+val2
? ? }
? ? print(add(val1: value, val2: value2))
}
func testFunAndBlock(){
? ? fun2(value: 1, value2: 2)
}//打印 3
Block
swift的block結(jié)構(gòu)如下家淤,{(參數(shù)列表)->返回值 in block實(shí)現(xiàn)},首先外邊由大括號包圍瑟由,內(nèi)部由關(guān)鍵字in分隔參數(shù)和實(shí)現(xiàn)部分
? ? let addBlock = {(value1:NSInteger, value2:NSInteger)->NSInteger in
? ? ? ? return value1 + value2
? ? }
? ? print(addBlock(1,2))
? ? //打印 3
—————————————————————————————————————————————————————————
當(dāng)block實(shí)現(xiàn)只有一行代碼時(shí)絮重,可以省略return關(guān)鍵字,默認(rèn)將此行代碼執(zhí)行結(jié)果返回歹苦。
? ? let addBlock = {(value1:NSInteger, value2:NSInteger)->NSInteger in
? ? ? ? value1+ value2
? ? }
? ? print(addBlock(1,2))
//等價(jià)于上面代碼
—————————————————————————————————————————————————————————
func fun3(value1:NSInteger, value2:NSInteger, addBlock:(NSInteger, NSInteger)->NSInteger) -> NSInteger {
? ? return addBlock(value1, value2)
}
func testFunAndBlock(){
? ? let number = fun3(value1: 1, value2: 2) { (val1:NSInteger, val2:NSInteger) -> NSInteger in
? ? ? ? return val1+val2
? ? }
? ? print(number)
}//打印 3
—————————————————————————————————————————————————————————
//定義一個(gè)函數(shù)青伤,參數(shù)傳入兩個(gè)int值,和一個(gè)操作block
func fun3(value1:NSInteger, value2:NSInteger, addBlock:(NSInteger, NSInteger)->NSInteger) -> NSInteger {
? ? return addBlock(value1, value2)
}
//調(diào)用函數(shù)傳參
? ? let number1 = fun3(value1: 1, value2: 2, addBlock: { (val1:NSInteger, val2:NSInteger) -> NSInteger in
? ? ? ? return val1+val2
? ? })
//可以省略addBlock的參數(shù)名字
? ? let number = fun3(value1: 1, value2: 2) { (val1:NSInteger, val2:NSInteger) -> NSInteger in
? ? ? ? return val1+val2
? ? }
//再簡化寫可以寫成如下效果完全一樣
let number2 = fun3(value1: 1, value2: 2){$0+$1}
逃逸block
當(dāng)一個(gè)block作為參數(shù)傳入一個(gè)函數(shù)中殴瘦,但是這個(gè)block在函數(shù)返回后才執(zhí)行狠角,我們稱這個(gè)block從這個(gè)函數(shù)中逃逸。
在參數(shù)名前標(biāo)記@escaping來標(biāo)記閉包蚪腋,表示這個(gè)閉包是可以逃逸的丰歌。
有一個(gè)使用場景:
如果函數(shù)內(nèi)是異步執(zhí)行的,但是閉包要在異步執(zhí)行完了以后再執(zhí)行屉凯,我們可以讓這個(gè)閉包逃逸出函數(shù)再執(zhí)行动遭。
func testFunAndBlock(){
? ? fun4 {
? ? ? ? print("hello")
? ? }
}
//執(zhí)行異步操作,延時(shí)十秒執(zhí)行block
func fun4(completeBlock:()->Void) {
? ? let deadLine = DispatchTime.now()+10
? ? DispatchQueue.main.asyncAfter(deadline: deadLine) {
? ? ? ? completeBlock()
? ? }
}//編譯出錯(cuò)Escaping closure captures non-escaping parameter ‘completeBlock'
//正確寫法加上@escaping
func fun4(completeBlock:@escaping()->Void) {
? ? let deadLine = DispatchTime.now()+10
//gcd 延時(shí)十秒操作
? ? DispatchQueue.main.asyncAfter(deadline: deadLine) {
? ? ? ? completeBlock()
? ? }
}
五神得、高級運(yùn)算符
溢出運(yùn)算符
? ? var value:UInt8 = 255;
? ? value = value+ 1;//編譯報(bào)錯(cuò) Arithmetic operation '255 + 1' (on type 'UInt8') results in an overflow
? ? var value:UInt8 = 255;
? ? value = value&+ 1;//編譯通過 value = 0
? ? value = value&- 1;//編譯通過 value = 255
? ? value = value&* 2;//編譯通過 value = 254
重載運(yùn)算符
prefix厘惦、infix、postfix自定義前綴運(yùn)算符、中綴運(yùn)算符宵蕉、后綴運(yùn)算符
prefix operator ++
prefix func ++ (value:NSInteger) -> NSInteger {
? ? return value + 1
}
? ? let value1 = ++3
? ? print(value1)
//打印 4
infix operator ++
func ++ (value1:NSInteger, value2:NSInteger) -> NSInteger {
? ? return value1*value1 + value2*value2
}
? ? let value1 = 1++3
? ? print(value1)
//打印10
postfix operator ++
postfix func ++ (value:NSInteger) -> NSInteger {
? ? return value + value
}
? ? let value1 = 3++
? ? print(value1)
//打印6
枚舉類型
enum Surname {
? ? case 張
? ? case 王
? ? case 李
? ? case 趙
}
? ? var sur:Surname = Surname.張
? ? sur =Surname.李
? ? switch sur {
? ? case .張:
? ? ? ? print(sur)
? ? case .王:
? ? ? ? print(sur)
? ? case .李:
? ? ? ? print(sur)
? ? case .趙:
? ? ? ? print(sur)
? ? default:
? ? ? ? print(sur)
? ? }//打釉途病:張