2.3、閉包

//: 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])

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容