1、閉包
Swift對閉包進行了簡化:
- 利用上下文推斷參數和返回值類型
- 隱式返回單表達式閉包,即單表達式閉包可以省略
return
關鍵字 - 參數名稱縮寫
- 尾隨(Trailing)閉包語法
先來看一個排序的例子,數組的降序排列
let usernames = ["Wangwu", "Lisi", "Xiaoming", "Zhangsan"]
func backWards(s1: String, s2: String) -> Bool
{
return s1 > s2
}
let resultName1 = usernames.sorted(by: backWards)
//resultName1: ["Zhangsan", "Xiaoming", "Wangwu", "Lisi"]
1.1 閉包表達式語法
{ (parameters) -> returnType in
statements
}
1.2 單表達式閉包隱式返回
單行表達式閉包可以通過省略return
關鍵字來隱式返回單行表達式的結果
let resultName2 = usernames.sorted { s1, s2 in s1 > s2 }
1.3 參數名稱縮寫
let resultName3 = usernames.sorted { $0 > $1 }
1.4 函數式閉包
let resultName4 = usernames.sorted(by: >)
2. 捕獲值(Capturing Values)
閉包可以在其被定義的上下文中捕獲常量或變量。即使定義這些常量和變量的原作用域已經不存在,閉包仍然可以在閉包函數體內引用和修改這些值。
3.閉包是引用類型(Closures Are Reference Types)
和類一樣,必要也是引用類型
4. 尾隨閉包(Trailing Closures))
尾隨閉包是一個書寫在函數括號之後的閉包表達式,函數支持將其作爲最後一個參數調用:
let numReult2 = caculateTwoNumbers(num1: 3, num2: 4) { $0 * $1 }
print(numReult2)
func caculateTwoNumbers(num1: Int, num2: Int, CaluFunction: (Int, Int) -> Int) -> Int{
return CaluFunction(num1, num2)
}
5. 逃逸閉包(@escaping)
func mainFunc(){
//調用函數
doSomething(paramClosure: {print("hello")})
doSomething(paramClosure:{print("word!")})
//逃逸調用閉包
for closurePrama in functionArray {
closurePrama()
}
//非逃逸閉包
someFunctionWithNonescapingClosure { (a) in
print(a)
}
}
//聲明一個存放函數的數組
var functionArray: [() -> Void] = []
//定義一個接收閉包參數的函數,如果定義非逃逸函數 func doSomething(@noescape paramClosure:() -> Void) 就會編譯錯誤
func doSomething(paramClosure:@escaping () -> Void){
//把參數放入數組中,用於逃逸調用
functionArray.append(paramClosure)
}
//非逃逸閉包 默認@noescape 可以省略不寫
func someFunctionWithNonescapingClosure(closure: (_ num:Int) -> Void) {
let a = 1
closure(a)
}
6、noescape是非逃逸的意思。
@noescape關鍵字代碼中扮演了一個標註的作用:來說明一個閉包參數,該閉包參數與此API是同步的,它只在此API中被調用。只要該API運行結束,該閉包的生命週期就結束。也就是說,該閉包逃不出該API的手掌心。哈哈哈哈!它對編譯器和API調用者來說:編譯器會對代碼做一些優化,而API調用者則可以放心大膽的使用該API,不用因爲擔心造成引用循環而去使用捕獲列表。同時在其中調用實例變量或實例方法的時候可以不使用"self."
但是!如何使用這個@noescape標註,這是需要正確的姿勢的!
上面的論述,只有在閉包是臨時創建,即沒有被API外部的任何其他屬性或全局變量持有的前提下才成立!!
func withLock(@noescape perform closure: () -> Void) {
myLock.lock()
closure()
myLock.unlock()
}
In Objective-C
- (void)performWithLock:(__attribute__((noescape)) void (^)())block { // exposed as @noescape to Swift
[myLock lock];
block();
[myLock unlock];
}
面試題:調用Masonry的block爲何不用weak?
原因就是使用了棧block,都是用NS_NOESCAPE修飾block.編譯器會相應地做一些優化,例如去掉一些多餘的對self
的捕獲、retain、release操作。
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;
- (NSArray *)mas_updateConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;