block表达式
类型:返回值类型(^block的名称)(block的参数)
返回值(^block变量名)(形参列表) = ^( 形参列表){
// 执行代码
};
NSString* (^blockName)(NSString *str) = ^(NSString *str){
return str;
};
NSLog(@"%@",blockName(@"block"));
闭包表达式
类型: (参数)->(返回值类型)
闭包名称 = { (形参列表) -> return 返回值 in
// 执行代码
}
let closure = { (str:String) -> String in
return str
}
print(closure("closure"))
//无参数无返回值
let closure = {()->Void in
print("closure")
}
closure()
//有参数无返回值
let closure = {(str:String) -> Void in
print(str)
}
closure("closure")
//无参数有返回值
let closure = {() -> String in
return "closure"
}
print(closure())
//有参数有返回值
let closure = { (str:String) -> String in
return str
}
print(closure("closure"))
下面例子通过使用几次迭代展示了 sorted(by:)
方法的定义和语法优化的方式。每一次迭代都用更简洁的方式描述了相同的功能
sorted(by:)
方法接受一个闭包,该闭包函数需要传入与数组元素类型相同的两个值,并返回一个布尔值来进行排序(Int, Int) -> Bool
let numbers = [1,9,2,8,3,7,4,6];
let numArr = numbers.sorted(by: callback)
print(numArr) //[1, 2, 3, 4, 6, 7, 8, 9]
func callback(_ num1:Int,_ num2:Int) -> Bool {
return num1 < num2
}
内联闭包参数和返回值类型声明与 callback(::) 函数类型声明相同
let numArr1 = numbers.sorted { (num1:Int, num2:Int) -> Bool in
return num1 < num2
}
print (numArr1) //[1, 2, 3, 4, 6, 7, 8, 9]
sorted(by:)
方法被一个Int
数组调用,因此其参数必须是 (Int, Int) -> Bool
类型的函数,因为所有的类型都可以被正确推断,所以返回箭头(->)和围绕在参数周围的括号也可以被省略
let numArr2 = numbers.sorted { num1, num2 in
return num1 < num2
}
print(numArr2) //[1, 2, 3, 4, 6, 7, 8, 9]
sorted(by:)
方法的参数类型明确了闭包必须返回一个 Bool
类型值,因为闭包函数体只包含了一个单一表达式(s1 > s2)
,该表达式返回Bool
类型值,因此这里没有歧义,return 关键字可以省略
let numArr3 = numbers.sorted { num1,num2 in num1 < num2 }
print(numArr3) //[1, 2, 3, 4, 6, 7, 8, 9]
let numArr4 = numbers.sorted {$0 < $1}
print(numArr4) //[1, 2, 3, 4, 6, 7, 8, 9]
Swift 的 Int
类型定义了关于大于号(>)的实现,其作为一个函数接受两个 Int 类型的参数并返回 Bool 类型的值。而这正好与 sorted(by:) 方法的参数需要的函数类型相符合。因此,可以简单地传递一个大于号
let numArr5 = numbers.sorted(by: <)
print(numArr5)
func closure(num:Int,a:() -> ()) -> Void {
print("多个参数")
}
//调用
closure(num: 3) {
print("闭包为最后一个参数")
}
func closure(a:() -> ()) -> Void {
print("只有一个参数且在最后")
}
//调用
closure {
print("闭包为最后一个参数")
}
闭包可以在其被定义的上下文中捕获常量或变量。即使定义这些常量和变量的原作用域已经不存在,闭包仍然可以在闭包函数体内引用和修改这些值。
func add(num:Int) -> ()->Int {
var value = 0
func result() -> Int{
value += num
return value
}
/*
这有一个叫做 add 的函数,其包含了一个叫做 result 的嵌套函数
嵌套函数result()从上下文中捕获了两个值,value 和 num
捕获这些值之后,add 将 result 作为闭包返回
每次调用 result 时,其会以 num 作为增量增加 value 的值
*/
return result
}
let result = add(num: 10)
print(result()) //10
print(result()) //20
print(result()) //30
//如果你创建了另一个result1,它会有属于自己的引用,指向一个全新、独立的value变量
let result1 = add(num: 10)
print(result1()) //10
//再次调用原来的result会继续增加它自己的value变量,该变量和result1中捕获的变量没有任何联系
print(result()) //40
//这两个常量或变量都引用相同的闭包
let method = result
(通俗点讲,不在当前方法中使用闭包,而是在方法之外使用)
@escaping
,用来指明这个闭包是允许“逃逸”出这个函数的@escaping
意味着你必须在闭包中显式地引用self
var result: ()->Void = {}
var str = ""
func show1(closure: @escaping () -> Void) {
result = closure
}
func show2(closure: () -> Void) {
closure()
}
func doSomething() {
show1 {self.str = "我是逃逸闭包"}
show2 {str = "我是普通闭包"}
}
//调用
doSomething()
print(str) //我是普通的闭包
result()
print(str) //我是逃逸的闭包
逃逸闭包是在函数执行之后再执行,于是这段代码最后输出“我是逃逸的闭包”
var arr = ["a","b","c"]
print(arr.count) //3
let block = {
arr.remove(at: 0)
}
print(arr.count) //3
print(block()) //a
print(arr.count) //2
函数接受一个显式闭包类型的参数
func delete(closure: ()->String){
print(closure())
}
var arr = ["a","b","c"]
delete(closure:{arr.remove(at: 0)}) //a
通过将参数标记为 @autoclosure
来接收一个自动闭包,该函数接受的是 String 类型参数而非闭包
func delete(closure: @autoclosure ()-> String){
print(closure())
}
var arr = ["a","b","c"]
delete(closure:arr.remove(at: 0)) //a