一、值类型、引用类型
1. 用 let 修饰 结构体实例的值类型
和 类实例的引用类型
时,分别修改它们的成员变量,能编译通过吗?
-
核心点:理解 let 修饰的实例,其内存是不可以改变的。
木有警告信息的就代表能编译通过
2. 方法和函数的区别?类、枚举、结构体
都能定义方法吗?
- 方法和函数没区别,是同一个东西
- 通常把定义在
类、枚举、结构体
内部的函数,叫做方法
3. 思考下面这个方法show
,它的本质是什么?在代码段如何存储的?(非常重要)
class Point {
var x = 11
var y = 22
func show() {
print(x,y)
}
}
var p = Point()
p.show()
- 上面类中的 show 方法,最终会其实会转变成
类似下面的函数
,存储在代码段
func show(self: Point) {
print(self.x, self.y)
}
4. 定义一个全局变量let a = 10
,在底层机器码阶段,只知道 a
的地址上是一个存储着 10
这个数据,程序是怎么标记它是 Int
类型呢?(一个困扰很久的问题 )
- 其实对于这个问题,我一开始就进入了误区。
- 在机器码阶段,它根本不关心
a
的地址上存储的数据是什么类型的,也不会存储任何类型相关的信息(类型在编译阶段应该保证的事情,有个符号表
)

5. 我们如何证明函数和方法(类中定义的函数),都是存放在代码段呢?

- 我们如上图所示打三个断点,进入
汇编调试
,可以拿到show 、 show1 、 &a
的地址值 - 可以发现
&a 是全局常量
,存放在全局区
,地址值大于 show 和 show1
-
show 和 show1
的地址值极其接近,所以大概率都存放在代码区
二、闭包
1. 在 Swift 中有两种方式定义函数,哪两种?
闭包表达式
func

2. 闭包表达式
通常用于参数传递,可以进行简写(理解下列简写过程)

3. 尾随闭包表达式?为什么要有?如何简写?
- 如果将一个
很长的闭包表达式
作为函数的最后一个参数
,使用尾随闭包可以增强函数的可读性
- 尾随闭包是一个被书写在函数调用括号外面(后面)的闭包表达式

- 如果闭包表达式是函数唯一实参,而且使用了尾随闭包的语法,那就不需要在函数名后边写圆括号

4. 闭包(Closure)是什么?
一个函数和它捕获的变量\常量环境组合起来,称为闭包
- 一般指定义在函数内部的函数
- 一般它捕获的是外层函数的局部变量\常量
5. 请问下面闭包输出是什么?

- 输出:
1 3 6 10
, 为什么呢? - num 被捕获会被拷贝到
堆内存
6. 如何证明 num 被拷贝到了堆内存呢?

-
获得以汇编代码的形式看断点代码:
断点1的汇编,没有形成闭包的情况
-
断点 2
断点 2,有闭包的情况
-
获得以汇编代码的形式看断点代码:
断点 2 汇编,有闭包的情况
-
对比
断点 1
和断点 2
的汇编,我们可以发现断点 2
出现了alloc 函数
-
alloc 函数
往往意味着堆空间的开辟
-
设置如下两个断点
我们给代码设置如下两个断点
-
var num = 0
这句代码可以获取 num 分配的内存地址,通常放在rax 寄存器
中,然后我们取消这个断点
获取 num 对象内的值

-
然后我们四次过掉剩下的断点,分别进行打印,发现和我们猜想非常一致,num 的值也经历的
0 1 3 6 10
的变化 -
借此充分证明了 num 被拷贝到了堆内存中,也解答了这个打印结果的问题
7. 如果上题中的 num 变成全局变量,会捕获吗?
- 不会进行捕获,找不到任何
alloc 相关的函数
- 其实也没必要进行捕获,因为可以正常访问
8. 为什么可以把闭包想象成一个类的实例对象?

9. 闭包
和 闭包表达式
有什么不同?
-
闭包表达式:
用于定义函数的方式之一 -
闭包:
一个函数和它捕获的变量\常量环境组合起来,称为闭包
10. 一道综合题,测试对闭包的理解,请说出输出值?

- 输出:

网友评论