本文主要介紹Swift的閉包的使用并與OC的Block做比較。學習Swift是繞不過閉包的,因為無論是全局函數(shù)還是嵌套函數(shù)都是閉包的一種,本文主要介紹閉包表達式。
1.閉包表達式的使用
// 1.定義一個閉包
let myClosure = {
(s1: String, s2:String) -> Bool
in
self.count = 10;
print("------");
return s1 > s2
}
print(count!);
// 2.調(diào)用閉包
let result = myClosure("Chris","Alex")
print("result = \(result)")
print("count = \(count!)")
日志
result = true
count = 10
總結(jié) :1.和oc的block的聲明和調(diào)用在形式上是極其類似的,不過閉包可以直接修改局部變量和全局變量的值,而block需要__block 關(guān)鍵字。
// 3.Tralling 閉包(尾隨)
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
( number) -> String in
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
print(strings);
日志
["OneSix", "FiveEight", "FiveOneZero"]
2.Trailing 閉包
函數(shù)的表現(xiàn)形式:(void)函數(shù)名(參數(shù))。如果一個函數(shù)的最后一個參數(shù)是一個閉包,允許你寫在參數(shù)所在哪個()外面。
(void)函數(shù)名(參數(shù)) {
};
如果只有閉包一個參數(shù),括號可以省略。變成:
(void)函數(shù)名 {
};
當閉包里的代碼很多的時候,這樣寫可以增加代碼的可讀性,多用于調(diào)用系統(tǒng)的函數(shù)。
舉例之前先介紹一下map函數(shù),map屬于Array的一個函數(shù),調(diào)用這個函數(shù)需要傳入一個閉包,返回一個新數(shù)組。Array里的每一個元素都會調(diào)用這個閉包,生成一個新對象,加入到新數(shù)組中。相當于 自動執(zhí)行了for in和addobject兩個方法,很實用。
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
使用Trailing 閉包之前
let strings = numbers.map({
( number) -> String in
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
})
使用Trailing 閉包之后
let strings = numbers.map{
( number) -> String in
var number = number
var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
就一個參數(shù)不明顯, 但是參數(shù)多了還是很有用的。因為閉包里的代碼一般有很多,會導致包含參數(shù)的()距離太遠。
3. 捕獲: 解決嵌套函數(shù)的循環(huán)引用
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
// 只能捕獲包含他的函數(shù)體內(nèi)的變量或常量的值,建立一個副本,相當于深拷貝
// 新變量
runningTotal += amount
return runningTotal
}
print(" ----- runningTotal = \(runningTotal)")
return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
print("incrementor = \(incrementByTen())")
print("incrementor = \(incrementByTen())")
print("incrementor = \(incrementByTen())")
打印
----- runningTotal = 0
incrementor = 10
incrementor = 20
incrementor = 30
總結(jié):incrementor里的runningTotal就是對:incrementor外的runningTotal的捕獲。捕獲有以下幾個特點。
(1)捕獲會生成一個新變量,和捕獲變量的值相等,但內(nèi)存不同,是引用類型,相當于OC中的深拷貝,新變量變化和捕獲的變量沒有任何關(guān)系了。因為incrementor外的runningTotal的值一直沒有改變。
(2)嵌套函數(shù)對新變量是強引用,只要嵌套函數(shù)還在,新變量就在,因為incrementor的返回值是一直增加的。
(3)如果不這樣為什么會造成循環(huán)引用,incrementor對makeIncrementor變量runningTotal的引用就是對makeIncrementor的引用。運用捕獲,就只是對runningTotal值的拷貝,不引用。
4.閉包傳值
在OC中我們用block最多的地方就是傳值了,同樣閉包也是。不過運用block和閉包傳值最好是當對象只有一個狀態(tài)的時候,如果對象狀態(tài)很多最好用代理。
CycleScrollView 往CycleScrollViewViewController進行傳值
import UIKit
// 定義閉包類型
typealias DidSelectItemClosureType = (Int) -> Void
class CycleScrollView: UIView, UICollectionViewDelegate,UICollectionViewDataSource {
// Mark:UICollectionViewDelegate
// 點擊方法
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if self.didSelectItemClosure != nil {
// 13.利用閉包傳值
self.didSelectItemClosure!(indexPath.row == 3 ? 0 : indexPath.row);
}
}
}
接收閉包傳過來的值
import UIKit
class CycleScrollViewViewController: UIViewController {
var cycleScrollView : CycleScrollView?
override func viewDidLoad() {
super.viewDidLoad()
createUI()
}
func createUI() {
self.automaticallyAdjustsScrollViewInsets = false;
cycleScrollView = CycleScrollView.init(frame: CGRect(x:0,y:64,width:ScreenWidth,height:ScreenHeight - 64))
// 閉包傳值
cycleScrollView?.didSelectItemClosure = {
(index : Int) -> Void in
print("您點擊了第 \(index) 個")
}
self.view.addSubview(cycleScrollView!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
如果傳值的例子有點沒看懂,可以去下載我的DEMO,里面有詳細的代碼。閉包還是很厲害的,不需要我們進行任何操作就解決了循環(huán)引用問題,不像block還得對變量進行弱引用。本文部分內(nèi)容是對Swift閉包詳解的整理。