一、汇编分析 fn1里面存放的东西
func testClosure2() {
class Person {
var age: Int = 10
}
typealias Fn = (Int) -> Int
var num = 0
func plus(_ i: Int) -> Int {
num += i
return num
}
return plus
} // 返回的plus和num形成了闭包
var fn1 = getFn()
print(fn1(1)) // 1
print(fn1(3)) // 4
var fn2 = getFn()
print(fn2(2)) // 2
print(fn2(4)) // 6
}
1.1 常规函数的分析
print(MemoryLayout.stride(ofValue: fn )) // 16 这个计算出来是16个字节
1.2 fn1 占用多少字节 不捕获变量的情况
但是 %rax 只能存8个字节,fun函数怎么返回16个的,进去看看
1.2 fn1 占用多少字节 捕获变量的情况 28
从下边可以看出alloc %rax 堆空间里面的地址都没有被修改
1.3 fn1 是怎么调用的
通过分析 在 fn1 里面的16 个字节 前八个存的是函数地址,后八个存的是堆地址,那么在这里函数调用就不会是 callq + 写死的地址 而是从上面的地址取出前8个函数地址来调用,对应就是下边的这里就是fn1 的调用
* %rax 的取值过程
1.4 fn1 参数传递 过程 50
1.5 num 是如何相加传进来的i的 51 是如何访问堆空间的mum 的
通过前面的分析,mum是存在对空间24个字节中的后8个字节中,那么我们就要看这里的后8个字节是怎么去到传进plus 函数的
上面的证明
查看事如何相加的
查看%rcx 是什么
查看0x10(%rdx)是什么
0x10(%rdx) 这里面%rdx加16 就是mum的值了
加完后是怎么又放进堆空间的 100
1.6 fn1 和 fn2
1.7 总结 1.01
1.8 什么时候捕获 1.16
是在return plus 的时候才捕获,所以在 num =11 和 num =14的时候,最终加出来的值以14为准
所以这里是15 因为最开始num 是14
汇编分析
所以要返回plus 的时候才捕获num的值,才分配对空间
所以最后捕获到num的值是14 ,因为在return 之前num 是14
1.9 num 是全局变量的是怎么样的?1.18
不会捕获,不会分配堆空间
为什么局部变量要分配堆空间,是要报住他的名
2.0 本来就在堆空间的是怎么捕获的
2.1 练习里面两个闭包的情况产生捕获 1.32
调用一次getFns 只会分配一份堆空看,里面的两个函数共享一份堆空间
左右对等
2.2 函数遍历的捕获
2.3 如果返回值是函数类型,那么参数的修饰要保持统一
func add(_ num: Int) -> (inout Int) -> Void {
func plus(v: inout Int) {
v += num
}
return plus
}
var num = 5
add(20)(&num) print(num)
2.4 自动闭包 2.04
2.4.1 有时候有可能返回,有可能不返回的情况
2.4.2 自动闭包 2.10
自动生成一个闭包,如写了@autoclosure 后, @autoclosure 会自动将 20 封装成闭包 { 20 }