//: Playground - noun: a place where people can play
import UIKit
/*
?閉包
?閉包(Closures)是自包含的功能代碼塊,可以在代碼中使用或者用來作為參數傳值。
?閉包相當于oc中的block,語法格式不一樣,但作用是一樣的
?主要是用于兩個類之間的異步回調
?閉包可看作是int、float一樣是一種數據類型,一種可以作為參數傳遞的數據類型
?格式:
?{
?(參數)-> 返回值類型 in
?執行語句
?}
?*/
//(1)一般形式
letcalAdd:(Int,Int)->(Int) = {
? ? (a:Int,b:Int)->Intin
? ? returna + b
}
calAdd(100,200)
//(2)簡化形式
//swift可以根據閉包上下文推斷參數和返回值的類型,所以上面的例子可以簡化如下
letcalAdd2:(Int,Int)->(Int) = {
? ? a,bin? // 也可以寫成(a,b) in
? ? returna + b
}
calAdd2(10,20)//省略了返回箭頭和返回值類型,以及參數周圍的括號
//(3)單行表達式閉包可以隱式返回,如下,省略return
letcalAdd3:(Int,Int)->(Int) = {(a,b)ina + b }
calAdd3(20,30)
//(4)如果閉包沒有參數,可以直接省略“in”
letcalAdd4:()->Int= {return1+2}
print("\(calAdd4())")
//(5)最簡單閉包 這個是既沒有參數也沒有返回值,所以return和in都省略了
letcalAdd5:()->Void= {
? ? print("既沒有參數也沒有返回值,所以return和in都省略了")
}
//(6)閉包內嵌函數 函數表達式作為回調函數
letsumMethod:(_a:Int,_b:Int)->(Int) = {
? ? (a,b) -> (Int)in
? ? varb = b
? ? funcchangeValue() -> (Int) {
? ? ? ? b += a
? ? ? ? returnb
? ? }
? ? return changeValue()
}
sumMethod(3, 4)
//補充----------------神奇的下劃線
//1.格式化數字字面量
//通過使用下劃線能夠提高數字字面量的可讀性,比如:
letpaddedDouble =123.000_001
letoneMillion =1_000_000
//2.忽略元組的元素值
//當我們使用元組時,假設有的元素不須要使用。這時能夠使用下劃線將對應的元素進行忽略,比如:
lethttp404Error = (404,"Not Found")
let(_, errorMessage) =http404Error
//3.忽略區間值
letbase =3
letpower =10
varanswer =1
for _ in 1...power {//只是為了算多次,不關心區間每一項的值
? ? answer *= base
//? ? print(answer)
}
//4.忽略外部參數名
//(1).忽略方法的默認外部參數名
//在用法(類方法或者實例方法)時,方法的第二個參數名及興許的參數名,默認既是內部參數名,又是外部參數名。假設不想提供外部參數名,能夠在參數名前加入下劃線來忽略外部參數名。
varcount:Int=0
funcincrementBy(amount:Int, numberOfTimes:Int){
? ? count+= amount * numberOfTimes
}
//在上面的代碼中,方法incrementBy()中的numberOfTimes具有默認的外部參數名:numberOfTimes,假設不想使用外部參數名能夠使用下劃線進行忽略,代碼能夠寫為(只是為了提高代碼的可讀性,一般不進行忽略):
varcount2:Int=0
funcincrementBy(amount:Int,_numberOfTimes:Int) {
? ? count2+= amount * numberOfTimes
}
//(2).忽略具有默認值的參數的外部參數名
//當函數(或者方法)的參數具有默認值時,Swift自己主動為該參數提供與參數名一致的默認外部參數名,因此在進行函數調用的時候,要提供默認參數名。能夠使用下劃線進行忽略默認外部參數名(可是不推薦忽略外部參數名。這主要是為了調用的時候能夠方便地知道每一個參數的含義)
funcjoin(s1:String, s2:String, joiner:String=" ") ->String{
? ? returns1 + joiner + s2
}
join(s1:"hello", s2:"swift", joiner:"-")
//假設不想使用默認外部參數名,能夠進行例如以下改動:
funcjoin2(s1:String, s2:String,_joiner:String=" ") ->String{
? ? returns1 + joiner + s2
}
join2(s1: "hello", s2: "world", "-")
join2(s1: "good", s2: "morning")
//(7)閉包內嵌閉包
letstrFormat:(_str1:String,_str2:String,_x:Int) ->Int= {
? ? (str1,str2,x)in
? ? letcalcute:(Int)->Int= {
? ? ? ? return$0
? ? }
? ? returncalcute(x)
}
strFormat("a", "b", 5)
//歸納:閉包類型是由參數和返回值決定,和函數一樣
//(8)起別名 關鍵字 typealias聲明一個閉包數據類型,類似于OC中的typedef別名
typealiasAddBlock = (Int,Int)->(Int)
letadd:AddBlock= {
? ? (a,b)in
? ? returna+b
}
add(5,5)
//(9)尾隨閉包 若將閉包作為最后一個參數,可以省略參數標簽,然后將閉包表達式寫在函數調用括號后面
functestFunction(testBlock:()->Void){
? ? testBlock()
}
testFunction(testBlock: {
? ? print("正常寫法")
})
testFunction(){
? ? print("尾隨閉包寫法")
}
testFunction {
? ? print("去掉括號的尾隨閉包寫法")
}
//值捕獲
//閉包可以定義在其被定義的上下文中捕獲常量或者變量,swift中可以捕獲值的形式比如嵌套函數,也就是定義在其他函數的函數體內
//逃逸閉包
//當一個閉包作為參數傳到一個函數中,需要這個閉包在函數返回之后才被執行,我們就稱該閉包從函數中逃逸,一般如果閉包在函數體內涉及到異步操作,但函數卻是很快就會執行完畢并返回的,閉包必須要逃逸掉,以便異步操作的回調
//逃逸閉包一般用于一部分回調函數的回調,比如網絡請求成功的回調和失敗的回調,語法仔函數的閉包行前加關鍵字@escaping
//示例1
funcrequestData(urlStrings :String,parameter : [String:Any],successData :@escaping(Any?)->(Void),failData :@escaping(Any?)->(Void)) {
? ? successData("請求成功")
? ? failData("請求失敗")
? ? print("函數體")
}
//示例2
varcomletionHandle:()->String= {"喜歡??看電影嗎?"}
funcdoSomething(some:@escaping()->String){
? ? comletionHandle = some
}
doSomething{
? ? return "喜歡"
}
print(comletionHandle())
//自動閉包
//顧名思義,自動閉包是一種自動創建的閉包,封裝一堆表達式在自動閉包中,然后將自動閉包作為參數傳給函數。而自動閉包是不接受任何參數的,但可以返回自動閉包中表達式產生的值。
//自動閉包讓你能夠延遲求值,直到調用這個閉包,閉包代碼塊才會被執行
var array = ["I","have","a","apple"]
print(array.count)
letremoveBlock = {
? ? array.remove(at:3)
}
print(array.count)
print("執行代碼塊移除\(removeBlock())")
//打印出"執行代碼塊移除apple" 這里自動閉包返回了apple值
print(array.count)
//閉包捕獲值
funcgetIncFunc(inc:Int) -> (Int) ->Int
{
? ? varmax =10
? ? funcincFunc(x :Int) ->Int{
? ? ? ? print("incFunc函數結束")
? ? ? ? returninc + x
//? ? ? ? max += 1
//? ? ? ? return max + x
? ? }
? ? // 當執行到這一句時inc參數就應該被釋放了, 但是由于在內部函數中使用到了它, 所以它被捕獲了
? ? // 同理, 當執行完這一句時max變量就被釋放了,但是由于在內部函數中使用到了它, 所以它被捕獲了
? ? print("getIncFunc函數結束")
? ? return incFunc
}
// 被捕獲的值會和與之對應的方法綁定在一起, 同一個方法中的變量會被綁定到不同的方法中
print("-------------")
letincFunc =getIncFunc(inc:5)
print(incFunc(2))
print(incFunc(5))
letincFunc2 =getIncFunc(inc:5)
print(incFunc2(5))
print("-------------")
//練習????????page707
//1、哪個句子最好描述一個閉包?3
//A最后一個函數在swift文件中。
//B可以全局執行的匿名函數。
//C可以作為變量存儲或作為參數傳遞的代碼塊。
//D可以在范圍內執行的指定代碼塊。
//4、以下哪一個不是一個接受閉包作為參數的函數?4
//5、5
//A map()返回與原始數組相同長度的新數組。
//B map()是一個對象的集合映射到其他對象的集合
//C、map()對數組中的每個對象執行一個閉包。
funcsumd(numberss:[Int]) ->Int{
? ? return 5
}
sumd(numberss: [2])
sumd(numberss: [11])