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;