Swift闭包

自包含(什么意思😂)的函数代码块
特点:捕获和存储上下文的任意常量和变量的引用

有三种闭包:

  • 全局函数:有名字,不捕获 (闭包性体现在哪里呢)
  • 嵌套函数:有名字,捕获封闭函数域内值
  • 闭包表达式:捕获上下文值得匿名闭包

Swift的闭包主张简洁,优化:

  • 利用上下文进行类型推断
  • 隐式返回单表达式闭包,闭包体只有单个表达式,可以省略return,返回值为表达式的值
  • 参数名称缩写
  • 尾闭包

闭包表达式

是一种利用简洁语法构建内联闭包的方式,语法为:

{ (parameters) -> returnType in
    statements
}

closure不能带标签(外部参数名),但是可以用_忽略(社么鬼?)

var closure = { (_ a:Int, b:Int) in
    print(a,b)
}

closure(1,2)

参数可以为in-out参数,但不能设定默认值,可以使用可变参数(必须放最后一位),假如不放最后一位呢?

var closure = { (a:Int..., b:Int) in
    print(a,b)
}

closure(11,11,22)//闭包无法调用,在定义closure时就该报错了

具体可以看http://stackoverflow.com/questions/39548852/swift-3-0-closure-expression-what-if-the-variadic-parameters-not-at-the-last-pl (没体会到意思😂,感觉有点不对)

我的理解:
为什么?因为闭包没有标签名,编译器无法知道可变参数有多长
放在最后一位的话,别的参数分配完了后,剩下的都是可变长参数的了

sorted方法
sorted(by: (String, String) -> Bool);//sorted方法原型

sorted不会对原数组产生影响,会产生一个新数组,sorted函数参数接受一个闭包,全局函数就是闭包:

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
var reversedNames = names.sorted(by: backward)

以上是全局函数的方式传递闭包

使用闭包表达式

reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

in关键字来分隔参数和闭包体,这种方式也叫内联闭包

上下文类型推断

闭包参数类型:根据数组内元素类型推断
闭包返回值:sorted已经指出
所以闭包可以省略类型

reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } )

其实,像这种内联闭包表达式作为函数参数,总是可以被推断类型,所以,总是可以省略

单表达式闭包隐式返回

闭包体中如果只有一个表达式,省略return,会返回这个表达式的值

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

参数名称缩写

我们不需要去定义s1和s2,可以使用名称缩写,$0,$1,$2按顺序表示参数表中的参数,所以参数表可以去掉,in也要去掉

reversedNames = names.sorted(by: { $0 > $1 } )

运算符方法

终极闭包

reversedNames = names.sorted(by: >)

尾闭包

一个书写在函数括号后的闭包表达式,遇见这种格式,函数会把闭包作为最后一个参数调用
使用条件:闭包表达式作为最后一个参数时,使用尾闭包增强可读性。
使用尾闭包时,不用写出函数的外部名

func abc(a:Int,closure:()->Void){
}

abc(a:1) {
} //使用尾闭包

abc(a:1,closure: {
})//不使用尾闭包

//当参数只有一个闭包表达式时,括号也可以省略
func abc(closure:()->Void){
}

abc{
}//使用尾闭包

sorted使用尾闭包

reversedNames = names.sorted() { $0 > $1 }
reversedNames = names.sorted { $0 > $1 }
func abc(closure:(Int,String)->Void){
    closure(1,"2")
}

abc { (tuple) in
    print(tuple)//tuple是一个按照参数表来的元组
}

思考问题:🤔如何让闭包调用时带有外部参数名?

Swift中的参数貌似只能是let型,除非使用in-out,如果想使用var,需要把let类型的常量值给var类型的变量值

值捕获

闭包可以捕获被定义上下文中的常量或者变量。即使这些值的作用域已经不在,闭包依然可以使用这些值(延长了值的生命周期)
嵌套函数可以捕获外部函数所有的参数以及定义的常量和变量

func xyz() -> ()->Void {
    var a = 1
    func abc(){//捕获a的引用
        a = a + 1
        print(a)
    }
    a = 100 //会影响到abc内的值
    abc()
    return abc
}
var m = xyz()//101
m()//102
m()//103

abc捕获了a的引用,xyz执行完毕后,a还在,因为abc延长了a的生命周期
注意类的循环引用,以后再做讨论

闭包是引用类型

常量值类型,常量引用类型的区别:

  • 常量值类型的一切都是常量,一旦确定不可更改
  • 常量引用类型的引用不可以改变,但是引用指向的对象是可以改变的

变量值类型,变量引用类型:

  • 都可以变

值类型和引用类型的本质:给值类型变量起个名字,这个名字就代表这个值,给引用类型变量起个名字,这个名字仅仅代表这个变量的引用,不能代表这个变量本身。还需要讨论

var a = 1//a是
var b = {
}//

值在传递时只能拷贝,引用在传递时可以只传递引用(其实是地址的拷贝)

逃逸闭包

闭包作为参数传递给函数,函数返回后,才执行这个闭包,我们称这个闭包为逃逸闭包。或者说作为函数参数的闭包可以在函数体外被调用叫做逃逸闭包。逃逸闭包必须指定@escaping
如何让闭包逃逸?把闭包保存在全局变量中,函数执行完毕后再调用闭包

var outcl:(()->Void)? //注意闭包类型的括号,没有括号就是返回值为Void?可选了

func taoyibibao(incl:@escaping ()->Void) {
    outcl = incl;
}

taoyibibao {
}

outcl!()//调用必须被初始化,所以`taoyibibao`需要先执行

逃逸闭包必须显式调用self

var outTaoyiCl:(()->Void)?

func taoyi(inTaoyiCl:@escaping ()->Void) {
    outTaoyiCl = inTaoyiCl
}

func butaoyi(inBuTaoyiCl:()->Void) {
    inBuTaoyiCl()
}

class A {
    var x:Int = 1
    func doSomeThing() {
        taoyi {
            self.x = 2 //逃逸出去的闭包必须显式使用self来捕获当前类实例
        }
        butaoyi {
            x = 2 //非逃逸闭包则可以省略self
        }
    }
}

自动闭包

使用条件:没有参数,返回闭包体中表达式的值

func abc(xyz:()->String) {
    print(xyz())
}

abc {"呵呵"}

改为自动闭包

func abc(xyz:@autoclosure ()->String) {
    print(xyz())
}

abc(xyz: "呵呵");//声明成自动闭包后,参数变为一个值(值或者返回值的表达式或者函数等),这个值会被自动转换成闭包

自动闭包就是调用形式变了,本来形参为闭包表达式,加了@autoclosure,就可以只传一个值或者表达式或者返回这种类型的函数调用。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代...
    穷人家的孩纸阅读 5,663评论 1 5
  • 闭包是功能性自包含模块,可以在代码中被传递和使用。Swift中的闭包与 C 和 Objective-C中的 blo...
    AirZilong阅读 2,695评论 0 2
  • 闭包可以从定义它们的上下文中捕获和存储对任何常量和变量的引用。 这被称为关闭这些常量和变量。 Swift处理所有的...
    Joker_King阅读 3,649评论 0 2
  • Swift 中的闭包是自包含的函数代码块,可以在代码中被传递和使用。类似于OC中的Block以及其他函数的匿名函数...
    乔克_叔叔阅读 3,437评论 1 3
  • 闭包是自包含的代码块,可以在代码中被传递和使用。Swift中的闭包与C和Objective-C中代码块(block...
    Raaaaamsey阅读 4,258评论 0 2