SWift学习笔记
闭包
闭包表达式
闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(b
locks)以及其他一些编程语言中的匿名函数比较相似。
闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称 闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。
函数实际上也是一直特殊的闭包,闭包采取以下三种形式:
- 全局函数是一个有名字但不会捕获任何值的闭包
- 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包
- 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包
闭包表达式语法有如下形式
{ (parameters) -> returnType in
statements
}
parameters可为常量,变量,inout,不能提供默认值。也可以在参数列表的最后使用可变参数。
元组也可以作为参数和返回值
exp:
let someClosure2:( String, String)->String = { (var s1:String , var s2:String)->String in
s1 += " "
s2 += "!"
return s1 + s2
}
任何情况下,通过内联闭包表达式构造的闭包作为参数传递给函数或方法时,都可以推断出闭包的参数和 返回值类型。 这意味着闭包作为函数或者方法的参数时,您几乎不需要利用完整格式构造内联闭包。
exp:
let someColsure3:(String,String)->String = { s1,s2 in
return s1+s2
}
单表达式闭包隐式返回(Implicit Return From Single-Expression Clossures)
单行表达式闭包可以通过省略 return 关键字来隐式返回单行表达式的结果.
let someColsure3:(String,String)->String = { s1,s2 in s1+s2}
Swift 自动为内联闭包提供了参数名称缩写功能,您可以直接通过 $0 , $1 , $2 来顺序调用闭包的参数,以此 类推。
let someColsure5:(String,String)->String = { $0 + $1}
尾随闭包
如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾
随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用:
func someFunctionThatTakesAClosure(closure: () -> Void) { // 函数体部分
}
// 以下是不使用尾随闭包进行函数调用 someFunctionThatTakesAClosure({
// 闭包主体部分 })
// 以下是使用尾随闭包进行函数调用 someFunctionThatTakesAClosure() {
// 闭包主体部分 }
exp:
func funTakeClosure(closure:(String,String)->String) -> String {
return closure("some", "closure")
}
let resault_cl = funTakeClosure({$0+$1})
let resault2_cl = funTakeClosure(){
$0 + "++" + $1
}
// 函数只有一个参数时 函数名后面的()括号也可以忽略
let resault3_cl = funTakeClosure{
$0 + "++" + $1
}
捕获值
闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可
以在闭包函数体内引用和修改这些值。
Swift 中,可以捕获值的闭包的最简单形式是嵌套函数,也就是定义在其他函数的函数体内的函数。嵌套函数可 以捕获其外部函数所有的参数以及定义的常量和变量。
func makeIncrementor(forIcrement amount:Int) -> ()->Int {
var runningTotal = 0;
func Incrementor()->Int{
runningTotal += amount
return runningTotal
}
return Incrementor;
}
var Incrementor = makeIncrementor(forIcrement: 5)
Incrementor()
// 返回结果 5
Incrementor()
// 返回结果 10
Incrementor = makeIncrementor(forIcrement: 10)
Incrementor()
// 返回结果 10
Incrementor()
// 返回结果 20
闭包是引用类型(Closures Are Reference Types)
无论您将函数或闭包赋值给一个常量还是变量,您实际上都是将常量或变量的值设置为对应函数或闭包的引用。
这也意味着如果您将闭包赋值给了两个不同的常量或变量,两个值都会指向同一个闭包:
let constIncrementor = Incrementor
Incrementor()
// 结果 30
非逃逸闭包(Nonescaping Closures)
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当 你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @noescape ,用来指明这个闭包是不允许“逃 逸”出这个函数的。将闭包标注 @noescape 能使编译器知道这个闭包的生命周期(译者注:闭包只能在函数体中 被执行,不能脱离函数体执行,所以编译器明确知道运行时的上下文),从而可以进行一些比较激进的优化。
var closures:[() -> Void] = []
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
closure()
//此处将报错
closures.append(closure)
}
自动闭包
自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,当它被调
用的时候,会返回被包装在其中的表达式的值。这种便利语法让你能够用一个普通的表达式来代替显式的闭
包,从而省略闭包的花括号。
自动闭包让你能够延迟求值,因为代码段不会被执行直到你调用这个闭包。延迟求值对于那些有副作用(Side Ef fect)和代价昂贵的代码来说是很有益处的,因为你能控制代码什么时候执行。
函数通过将参数标记为@autoclosure 来接收一个自动闭包.
func funAutoclosure(@autoclosure closure:()->String) -> String {
return closure()
}
var autoclosureArry = ["auto", "closure", "string", "func"]
funAutoclosure(autoclosureArry.removeLast())
@autoclosure 特性暗含了 @noescape 特性,这个特性在非逃逸闭包 (页 0)一节中有描述。如果你想让这个闭包 可以“逃逸”,则应该使用 @autoclosure(escaping) 特性.