您的位置:首页 > 移动开发 > Swift

Swift2-0基础_Closures(闭包)

2016-04-15 18:44 351 查看
import Foundation
print("Hello, World!")
// 闭包和OC中的Blcok类似
// 1 闭包表达式
// sort 方法
/*
Swift 标准库提供了名为 sort 的方法,会根据您提供的用于排序的闭包函数将已知类型 数组中 的值进行排序。
一旦排序完成, sort(_:) 方法会返回一个与原数组大小相同,包含同类型元素且元素已正确排序的新数组。
原数组不会被 sort(_:) 方法修改

sort(_:) 方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔类型值来表明当排序结束后传入的第一个参数排在第二个参数前面还是后面。
如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回 true ,反之返回 false
*/
let names = ["A","F","D","C"]
func backwards(s1:String, s2:String) -> Bool {
return s1 > s2;
}
var newNames = names.sort(backwards)
print(newNames)     // ["F", "D", "C", "A"]

// 闭包表达式语法
/*
{
(parameters) -> returnType in
statments
}
闭包表达式语法可以使用常量、变量和 inout 类型作为参数,不能提供默认值。也可以在参数列表的最后使用可变参数。元组也可以作为参数和返回值
*/
// 在内联闭包表达式中,函数和返回值类型都写在大括号内
newNames = names.sort({ (s1:String, s2:String) -> Bool in
return s1 > s2
})

// 根据上下文推断类型
/*
因为排序闭包函数是作为 sort(_:) 方法的参数传入的,Swift 可以推断其参数和返回值的类型。
sort(_:) 方法 被一个字符串数组调用,因此其参数必须是 (String, String) -> Bool 类型的函数。
这意味着 (String, String) 和 Bool 类型并不需要作为闭包表达式定义的一部分。
因为所有的类型都可以被正确推断,返回箭头( -> )和 围绕在参数周围的括号也可以被省略:
*/
newNames = names.sort({ s1, s2 in return s1 > s2})
/*
sort(_:) 方法的第二个参数函数类型明确了闭包必须返回一个 Bool 类型值。
因为闭包函数体只包含了一个单一表达式( s1 > s2 ),该表达式返回 Bool 类型值,因此这里没有歧义, return 关键字可以省略
*/
newNames = names.sort({ s1, s2 in s1 > s2})

// 参数名称缩写
// Swift 自动为内联闭包提供了参数名称缩写功能,您可以直接通过 $0 , $1 , $2 来顺序调用闭包的参数,以此类推。
// 如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 in 关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成:
newNames = names.sort({ $0 > $1 })

// 运算符函数
// Swift 的 String 类型定义了关于大于号( > )的字符串实现,其作为一个函数接受两个 String 类型的参数并返回 Bool 类型的值
newNames = names.sort( > )

// 2 尾随闭包
func someFunctionThatTakesAClosure(closure:() -> Void) {
// 函数体部分

}
// 非尾随闭包
someFunctionThatTakesAClosure({
// 闭包主体部分

})
// 尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分

}

newNames = names.sort() {
$0 > $1
}
// 尾随闭包可以省略 ()
newNames = names.sort {
$0 > $1
}

// 例子
/*
Swift 的 Array 类型有一个 map(_:) 方法,其获取一个闭包表达式作为其唯一参数。
该闭包函数会为数组中的每一个元素调用一次,并返回该元素所映射的值。
具体的映射方式和返回值类型由闭包来指定
*/
let digitNames = [
0:"Zero",1:"One",2:"Two",3:"Three",4:"Four",
5:"Five",6:"Six",7:"Seven",8:"Eight",9:"Nine"
]
let numbers = [28,36,520]
/*
字典下标后跟着一个叹号(!),因为字典下标返回一个可选值(optional value),表明该键不存在时会查找失败。
由于可以确定 number % 10 总是 digitNames 字典的有效下标,因此叹号可以用于强制解包 (force-unwrap) 存储在下标的可选类型的返回值中的 String 类型的值
*/
let numEngString = numbers.map() {
(var number) -> String in var output = ""
while number > 0 {
output = digitNames[number % 10]! + output
number /= 10
}
return output
}
print(numEngString)

// 3 捕获值
/*
闭包可以在其被定义的上下文中捕获常量或变量。
即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值

Swift 中,可以捕获值的闭包的最简单形式是嵌套函数,也就是定义在其他函数的函数体内的函数。
嵌套函数可 以捕获其外部函数所有的参数以及定义的常量和变量
*/
// 外函数返回类型为 () -> Int 返回一个函数,该函数在每次调用时不接受参数,只返回一个 Int 类型的值
func makeIncrementor(forIncremnet amount:Int) -> () -> Int {
var runningTotal = 0
// incrementor() 并没有任何参数,但是在函数体内访问了 runningTotal、amount 变量
// 从外围函数捕获到了变量的引用,捕获引用保证了变量在调用完后不会消失,并且保证下一次执行内函数的时候,参数依 runningToltal 旧存在
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
// 定义了一个叫做 incrementByTen 的常量,该常量指向一个每次调用会将 runningTotal 变量增加 10 的 ementor 函数
let incrementByTen = makeIncrementor(forIncremnet: 10)
print(incrementByTen())     // 10
// 创建了一个全新的,独立的 runningTotal 变量
let incrementBySeven = makeIncrementor(forIncremnet: 7)
print(incrementBySeven())   // 7
// 依旧调用原来的变量
print(incrementByTen())     // 20

// 闭包是引用类型
// incrementBySeven 和 incrementByTen 是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量的值。这是因为函数和闭包都是引用类型。
let againIncrementByTen = incrementByTen()
print(againIncrementByTen)  // 30

// 非逃逸闭包
/*
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸
当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @noescape ,用来指明这个闭包是不允许“逃逸”出这个函数的
*/
func someFunctionWithNoescapeClosure(@noescape closure: ()->Void) {
closure()
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: