首页 > 其他分享 >Swift闭包简要概述

Swift闭包简要概述

时间:2022-12-04 21:31:39浏览次数:38  
标签:闭包 简要 函数 Int runningTotal var Swift 变量

1.闭包

闭包是一个捕获了外部变量或者常量的函数,可以有名字的函数,可以是匿名的函数,也可以是不捕获外部变量的函数。所以可以说闭包是特殊的函数。

闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 ObjC 中的代码块(blocks)比较相似。



捕获的变量,可以写在捕获列表里. 如果使用捕获列表,即使省略了参数名字、参数类型、返回类型,也必须要用 in 的关键字

●捕获列表里面的是捕获的是值,不可变,

●未在捕获列表里,捕获到的是地址,可以修改


案例1: 闭包内部不能修改值传递的

Swift闭包简要概述_swift5


案例2: 闭包外部修改值传递的数据,也是无效的

Swift闭包简要概述_swift闭包_02



2. 闭包表达式

下面这种,是我们熟知的闭包表达式:一个匿名函数 + 捕获了外部的变量或者常量: 

{ (age: Int) -> Int in 
return age + 1
}

闭包表达式还可以按照下面的规则,变的更加简洁:

●如果参数及返回值类型可以根据上下文推断出来,则可以省略参数 / 返回值的类型

●如果只有一行,是单表达式,可以省略 return 关键字

●参数的名称可以根据参数的位置,简写成 $0、$1

●如果最后一个参数是闭包,可以使用尾随闭包表达式

●如果只有一个参数,且是闭包,可以省略小括号,直接写尾随闭包

var array = [1, 2, 3]

// 常规写法
array.sort(by: {(item1 : Int, item2: Int) -> Bool in return item1 < item2 })
// 省略参数类型
array.sort(by: {(item1, item2) -> Bool in return item1 < item2 })
// 省略返回值类型
array.sort(by: {(item1, item2) in return item1 < item2 })
// 省略 return 关键字
array.sort(by: {(item1, item2) in item1 < item2 })
// 省略小括号(尾随闭包)
array.sort{(item1, item2) in $0 < $1 }
// 省略参数,使用默认的$0 $1
array.sort{ $0 < $1 }
// 甚至整个闭包表达式,只剩下一个 < 符号
array.sort(by: <)

闭包可以当做类型使用,也就是可以用来定义变量、参数、返回值

// 定义变量
var closure : ((Int) -> Int)?
closure = { (age: Int) -> Int in
return age + 1
}

// 定义参数
func test(param: ((Int) -> Int)) {
print(param())
}

// 作为返回值
func getClosure() -> ((Int) -> Int) {
var closure : ((Int) -> Int) = { (age: Int) -> Int in
return age + 1
}
return closure
}

3.尾随闭包

当函数的最后一个参数是闭包时,可以使用尾随闭包来增强函数的可读性。在使用尾随闭包时,你不用写出它的参数标签:

func test(closure: () -> Void) {
...
}

// 不使用尾随闭包
test(closure: {
...
})

// 使用尾随闭包
test() {
...
}

4.逃逸闭包

逃逸闭包是指闭包作为参数传入函数中,然而它的生命周期比函数的声明周期还长,也就是闭包需要在函数释放后也可以调用,我们就称这个闭包为逃逸闭包。编译器默认闭包为非逃逸闭包,用@nonescaping修饰。逃逸闭包使用@escaping 修饰。

var completions: [() -> Void] = []
func testClosure(completion: () -> Void) {
completions.append(completion)
}

此时编译器会报错,提示你这是一个逃逸闭包,我们可以在参数名之前标注 @escaping,用来指明这个闭包是允许“逃逸”出这个函数的。

var completions: [() -> Void] = []
func testEscapingClosure(completion: @escaping () -> Void) {
completions.append(completion)
}

另外,将一个闭包标记为 @escaping 意味着你必须在闭包中显式地引用 self,而非逃逸闭包则不用。这提醒你可能会一不小心就捕获了self,注意循环引用。


有两种情况需要使用逃逸闭包:

●闭包被赋值给属性或者成员变量

●在延时后,使用闭包

4.1 闭包被赋值给属性或者成员变量

class LGTeacher{
var age = 18
var complitionHandler: ((Int)->Void)?

func makeIncrementer(amount: Int, handler: @escaping (Int) -> Void){
var runningTotal = 0
runningTotal += amount

self.complitionHandler = handler
}

func doSomething(){
self.makeIncrementer(amount: 10) {
//会引起循环引用
// self.age = 20
print($0)
}
}

deinit {
print("LGTeaher deinit")
}
}

func test() {
let t = LGTeacher()
t.doSomething()
t.complitionHandler?(50)
}

test()

4.2 延时执行逃逸闭包

func makeIncrementer(amount: Int,  handler: @escaping (Int) -> Void){
var runningTotal = 0
runningTotal += amount

self.complitionHandler = handler
// 延时执行
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
self.complitionHandler?(50)
}
}

5. 自动闭包

解释1:

当闭包作为参数传入时,使用@autoclosure来修饰,就表示如果传入的是一个普通的值,就会被自动包装成一个闭包。这个闭包没有参数,返回值是String, 也就是我们传入的普通的字符串。

解释2:

自动闭包是一种自动创建的闭包,用于包装传递给函数作为参数的表达式。这种闭包不接受任何参数,让你能够省略闭包的花括号,用一个普通的表达式来代替显式的闭包。

并且自动闭包让你能够延迟求值,因为直到你调用这个闭包,代码段才会被执行。要标注一个闭包是自动闭包,需要使用@autoclosure。

例1:
func debugOutPrint(for condition: Bool , _ message: @autoclosure () -> String){
if condition {
print(message())
}
}

func doSomething() -> String{
//do something and get error message
return "NetWork Error Occured"
}
debugOutPrint(for: true, doSomething())
debugOutPrint(for: true, "Application Error Occured")

例2:
// 未使用自动闭包,需要显示用花括号说明这个参数是一个闭包
func test(closure: () -> Bool) {
}
test(closure: { 1 < 2 } )

// 使用自动闭包,只需要传递表达式
func test(closure: @autoclosure () -> String) {
}
test(customer: 1 < 2)

6.闭包捕获的变量的内存结构

我们通过下面这个例子,来探索闭包捕获的变量的内存结构:

func makeIncrementer() -> () -> Int {
var runningTotal = 12
func incrementer() -> Int {
runningTotal += 1
return runningTotal
}
return incrementer
}

标签:闭包,简要,函数,Int,runningTotal,var,Swift,变量
From: https://blog.51cto.com/u_15566227/5910072

相关文章

  • 闭包的使用场景
     functionfa(){letcon="闭包的内容";functionfb(){console.log(con);}returnfb;}letcontent=fa()();content;//闭包的内容......
  • SwiftUI 常见组件示例
    基础组件TextText("Hamlet").font(.largeTitle)Text("byWilliamShakespeare").font(.caption).italic()ImageHStack{Image(systemName:"fol......
  • ABC250简要题解
    重点在于简要A,B,C,语法题,跳了。D是埃筛求个质数枚举一下,跳了、E神秘的哈希。对于前\(i\)个数搞个可加哈希,这样能\(O(1)\)比较。给了个神秘的哈希方式是\(\suma......
  • JOISC 2021 简要题解
    「JOISC2021Day1」饮食区维护\(n\)个队列,支持\(m\)次操作:在\([l,r]\)号队列的尾端均加入\(k\)个颜色\(c\)的球。将\([l,r]\)号队列的前\(k\)个球pop......
  • Swift的基础之关于“!”和“?”的使用介绍
    swift编程,不外乎是定义属性或者函数(方法),访问属性或者调用函数,类型转换,?和!在这几个过程中,都有一展身手的时候,而且,每次要考虑使用的时候,它们俩都会一起出现在我们的大脑中,用还......
  • Swift 2023:强调并发、泛型和 C++ 互操作性,开发 Swift 解析器
    AppleSwift团队的一名工程师兼语言工作组成员JohnMcCall在最新发布的一篇博客中介绍了Swift的2023年度计划。“Swift项目中有很多激动人心的工作正在进行,而且很......
  • 最小环与传递闭包
    最小环求无向图的最小环长度。在无向图中最小环长度不小于\(3\)。使用Floyd算法,可以在带权图上跑,但是时间复杂度为\(O(n^3)\)。考虑\(f[k][i][j]\)为表示\(i......
  • Swift基础之封装蒙版指导视图
    相信大家都见到过,一个软件添加了新功能,会给用户使用步骤指导,所以我针对这个功能,便于使用的小demo,希望对大家有帮助。源码中的注释比较详细,这里不再赘述,自行研究:varimageNam......
  • Swift基础之实现下拉变大和OC下拉变大上拉缩小Demo
    Swift语言实现下拉变大效果:(上拉缩小效果随后研究......)关键代码:方法一:self.automaticallyAdjustsScrollViewInsets=false;              tableViewW=UI......
  • Swift基础之封装一个WebViewController
    研究了一段时间,总算搞定了这个功能封装,现在给大家分享一下,具体看代码,上面有对应的文字描述,有问题请留言,下载源码,请帮忙点一下star,给点继续分享的动力,谢谢~/**//swift中......