感谢作者
https://www.jianshu.com/p/098d40b8bca5
// Closures:闭包
// 全局函数和嵌套函数实际上是闭包的特例。闭包采用以下三种形式之一:
// 全局函数是具有名称但不捕获任何值的闭包。
// 嵌套函数是具有名称并且可以从其封闭函数中捕获值的闭包。
// Closure表达式是一种未命名的可以从周围的上下文中捕获值的闭包,用轻量级语法编写。
// Swift的闭包表达式鼓励简洁,因此闭包具备:
// 从上下文中推断参数和返回值类型
// 单表达式闭包的隐式返回
// 简洁的参数名称
// 尾随闭包语法
// 闭包表达式语法
// { (parameters) -> <#returnType#> in <#statements#> }
// 闭包表达式语法中的参数可以是输入输出参数,但不能具有默认值。
// 可以使用变量(variadic)参数。元组也可以用作参数类型和返回类型。
// 排序数组
// 内联闭包
// 对于内联闭包表达式,参数和返回类型写在花括号内,而不是在花括号外。
// 闭包的方法体的开头由in关键字引入。这个关键字表示闭包的参数
// 和返回类型的定义已经完成,闭包的方法体即将开始。
let nms = ["Chris", "Alex", "Ewa", "Barry", "Daniella"];
let newArray1 = nms.sorted(by: {(s1:String, s2:String) -> Bool in
return s1 > s2;
});
// 因为字符串数组的排序
// 所以参数类型可推导,省略参数类型
let newArray2 = nms.sorted { (s1, s2) -> Bool in
return s1 > s2;
}
// 单表达式 返回值类型推导,省略返回值类型
let newArray3 = names.sorted(by: {s1,s2 in s1 > s2});
// 简写参数名称
// 简写参数名称,可通过名称$ 0,$ 1,$ 2等引用闭包参数的值。
// 如果在闭包表达式中使用这些简写参数名称,则可以从闭包表达式中
// 省略闭包的参数列表,并将通过函数类型推断简写的参数名称的数量和类型。
// in关键字也可以省略。
let newArray4 = names.sorted(by: {$0 > $1});
// 操作符方法
// 上面的闭包表达式实际上有一种更简短的方式来编写。
// Swift的String类型将其大于运算符>的实现,定义为具有
// 两个String类型参数的方法,并返回Bool类型的值。
// 这与sorted(by :)方法所需的方法类型完全匹配。
// 因此,可以简单地传入运算符>
let newArray5 = names.sorted(by: >);
print(newArray1); //!< ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
// 尾随闭包
trailingClosures(parameter: "不是尾随闭包写法1", block: blockFunction);
trailingClosures(parameter: "不是尾随闭包写法2", block: {(parameter:String)->Void in print(parameter);
});
trailingClosures(parameter: "不是尾随闭包写法3", block: {(parameter) in print(parameter);});
//!< 参数类型和返回值可以根据函数类型得知,故可以省略
//尾随闭包写法的调用形式,block函数标签不能出现在圆括号内
trailingClosures(parameter: "尾随闭包的写法") { (parameter) in
print(parameter);
};
// sorted(by :)的尾随闭包的写法
let newArray6 = names.sorted(){s1,s2 in s1 > s2};
let newArray7 = names.sorted(){$0>$1};
let newArray8 = names.sorted{s1,s2 in s1 > s2};
let newArray9 = names.sorted{$0>$1};
// 值的捕获
// increaseByTen其实是内部的嵌套函数(闭包的一种),
// 捕获了`createIncrementer`方法的参数`amount`与方法体中定义的`total`变量。
let increaseByTen = createIncrementer(forIncrese: 10);
print(increaseByTen()); //!< log:10
print(increaseByTen()); //!< log:20
print(increaseByTen()); //!< log:30
// 综上述`increaseByTen`函数捕获了捕获了`createIncrementer`方法的参数`amount`
// 与方法体中定义的`total`变量,并在其内部持有了外部变量`total`和外部方法参数`amount`的副本。
// 以至于`increaseByTen`可以每次调用都能基于`amount`的值,对变量`total`进行递增,
// 并且返回结果。
let increaseBySix = createIncrementer(forIncrese: 6)
print(increaseBySix())//!< log:6
print(increaseBySix())//!< log:12
print(increaseBySix())//!< log:18
// 综上述:`increaseBySix`是调用了`createIncrementer`生成的一个`()->Int`类型的常量。
// 在生成的过程中,内部的闭包(嵌套函数)`increase`重新捕获了外部变量`total`
// 和外部方法参数`amount`,并返回此方法赋值给了`increaseBySix`,
// 以至于`increaseBySix`和`increaseByTen`具备不同的递增系数。
// 本质上这是两个不同的函数类型的常量。
// 闭包是引用类型
// 函数和闭包是引用类型
let alsoIncreaseByTen = increaseByTen; //!< 引用传递
print(alsoIncreaseByTen()); //!< log:40
let alsoIncreaseByTen1 = increaseByTen;
print(alsoIncreaseByTen1()); //!< log:50
// 逃逸闭包
// 当一个函数需要用到异步操作回调的时候需要使用逃逸闭包。
//调用
escapeClosure.startEscape();
//!< 场景1逃逸闭包1被调用了 场景2逃逸闭包2被调用了
// 自动闭包:Autoclosures
var nameArray = ["赵云","关羽","张飞","刘备"];
//闭包参数为空 被省略 返回值是String类型由`nameArray.remove(at: 0)`的返回值决定 故省略,同时省略了`in`关键字
let removeClosure = {
nameArray.remove(at: 0);
};
print("调用`removeClosure`移除之前,数组`nameArray`的个数:\(nameArray.count)。调用`removeClosure`之后移除了字符串:\(removeClosure()) ,数组`nameArray`的个数变为:\(nameArray.count)。综上述可以看出自动闭包允许延迟调用,因为在调用闭包之前,内部代码不会运行");
// 将闭包作为参数传递给函数时,在函数中进行数据元素移除的操作
escapeClosure.unknownOperate { () -> String in
nameArray.remove(at: 0);
};
// 更简化的形式
escapeClosure.unknownOperate {nameArray.remove(at: 0)};
// 调用很神奇啊,但也会让人很蒙 有木有
escapeClosure.autoClosure(operation: nameArray.remove(at: 0));
//调用
escapeClosure.doAutoclosureAndEscape();
//!< 自动闭包逃逸
/*控制台输出:
我是可逃逸的自动闭包:0号
我是来自数组的可逃逸的自动闭包:1号
*/
class escapeClosure: NSObject {
//声明一个闭包类型的数组
var closureArray : [(String)->Void] = []
override init() {
super.init()
}
//模仿闭包逃逸:写完 closureArray.append编译器检测到时逃逸闭包提示添加@escaping
func escapeClosures(title:String,handle:@escaping (String)->Void){
closureArray.append(handle)
}
//类方法
static func startEscape(){
let escapeObject = escapeClosure()
escapeObject.escapeClosures(title: "场景1") { (s1) in
print("场景1"+s1)//!< 场景1逃逸闭包1被调用了
}
escapeObject.escapeClosures(title: "场景2") { (s1) in
print("场景2"+s1)//!< 场景2逃逸闭包2被调用了
}
//使用迭代器进行下标和元素的同时遍历
for (index,obj) in escapeObject.closureArray.enumerated() {
obj("逃逸闭包\(index+1)被调用了")
}
}
// 延迟调用的另一种形式,定义个拟合自动闭包的函数类型作为参数的函数。
// 先定义闭包,随后在函数体内调用获取值。
static func unknownOperate(operation:()->String) -> Void {
print("闭包作为参数,输出的删除的数组的字符串:\(operation())");
//<!闭包作为参数,输出的删除的数组的字符串:赵云
}
//定义一个自动闭包的形式
static func autoClosure(operation: @autoclosure ()->String){
print("自动闭包作为参数,输出的删除的数组的字符串:\(operation())");
}
//定义存储自动闭包类型的数组变量
var autoclosureArray : [()->String] = [];
//自动闭包实现逃逸
func autoclosureAndEscape(handle: @autoclosure @escaping ()->String) -> Void {
autoclosureArray.append(handle);
}
//执行自动闭包逃逸操作
static func doAutoclosureAndEscape(){
var nameArray = ["我是来自数组的可逃逸的自动闭包"];
//实例化对象
let escapeObj = escapeClosure();
escapeObj.autoclosureAndEscape(handle: "我是可逃逸的自动闭包");
escapeObj.autoclosureAndEscape(handle: nameArray.remove(at: 0));
//逃逸闭包的调用,在函数返回后
for (index,handle) in escapeObj.autoclosureArray.enumerated() {
print("\(handle()):\(index)号");
}
}
}
网友评论