您现在的位置是:首页 >学无止境 >swift闭包底层本质网站首页学无止境
swift闭包底层本质
简介swift闭包底层本质
swift学习笔记
闭包底层原理
1、函数赋值给一个变量
func getFn(_ a: Int) -> Int {
return a + 1
}
let funcVar = getFn
- 当在把一个函数赋值给一个变量funcVar的时候,funcVar变量会存储两个东西
- funcVar总共占用16个字节
- 前八个字节存储着getFn的函数地址
- 后八个字节存储着0
- 这种情况下暂时是没用到的,因此是0这种空值
- 当在闭包当中就有大大的用处
2、 闭包捕获一个变量时赋值给一个变量
func getFn() -> (Int) -> (Int) {
var num = 0
func plus(_ a: Int) -> Int {
num += a
return num
}
return testClosure
}
let plus = getFn()
plus(1)
plus(2)
- 当把捕获一个变量的闭包赋值给一个变量plus的时候,plus变量也同样会存储两个东西
- plus总共占用16个字节
- 前八个字节存储着plus闭包的函数地址
- 后八个字节存储捕获到的num的信息,并且此信息存储在堆空间
- 此时的num已经被包装成一个对象了
- 其拥有24个字节
- 前八个字节存储着类似isa的东西
- 中间八个字节存储着引用计数
- 最后八个字节就是num
- 当在调用plus(1)的时候,会找到其存储的前八个字节,也就是闭包的函数地址,进行函数调用
- 调用的时候,会传入两个参数
- 一个是1
- 另一个就是捕获的堆空间的num
3、闭包捕获多个变量时赋值给一个变量
func getFn() -> (Int) -> (Int) {
var num = 5
var num1 = 6
func plus(_ a: Int) -> Int {
num += a
num1 += 1
return num + num1
}
return plus
}
let plus = getFn()
plus(1)
- 当把捕获两个变量的闭包赋值给一个变量plus的时候,plus变量也同样会存储两个东西
- plus总共占用16个字节
- 前八个字节存储着plus闭包的函数地址
- 后八个字节存储捕获到的num和num1的信息,并且此信息存储在堆空间
- 此时的num和num1共同被被包装成一个对象了
- 其拥有32个字节
- 第一个八字节存储着类似isa的东西
- 第二个八字节存储着引用计数
- 第三个八字节存储的是被包装成对象的num信息
- 拥有24个字节
- 前八个字节存储着类似isa的东西
- 最后八个字节存储的就是num
- 第三个八字节存储的是被包装成对象的num1信息
- 拥有24个字节
- 前八个字节存储着类似isa的东西
- 最后八个字节存储的就是num1
- 当在调用funcVar(1)的时候,会找到其存储的前八个字节,也就是闭包的函数地址,进行函数调用
- 调用的时候,会传入两个参数
- 一个是1
- 另一个就是捕获的堆空间的num
4、闭包捕获多个值,并且返回多个函数
func getFn() -> ((Int) -> (Int), (Int) -> (Int)) {
var num = 5
var num1 = 6
func plus(_ a: Int) -> Int {
num += a
num1 += 1
return num + num1
}
func minus(_ a: Int) -> Int {
num += a
num1 += 1
return num - num1
}
return (plus, minus)
}
let (plus, minus) = getFn()
plus(1)
plus(2)
minus(1)
minus(2)
- 这种情况就跟上面那种情况是一样的。可以理解成每返回一个闭包就是有一个上面那种情况的内存信息
- 因此这里返回两个闭包,就是有两个上面一样的内存信息
- 只是他们指向的num对象信息相当于是一样的
5、闭包捕获class对象
func getObjFn() -> (Int) -> (Int) {
var num = 5
var obj = FnObj()
obj.a = 3
func plus(_ a: Int) -> Int {
num += a
obj.a += 1
return num + obj.a
}
return plus
}
let plus = getObjFn()
plus(1)
- 对变量的捕获方式跟捕获普通变量几乎一样
- 只是捕获class对象的时候,不会再次对class对象进行包装
- 因为要放在堆上面,因此普通变量会包装成class对象
- class对象本身就是class对象,因此不需要再次包装
- 因此其实对class对象的捕获相对来说更简单
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。