类与结构体-初识

147 阅读4分钟

类与结构体-初识

在Swift标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分

比如Bool、Int、Double、String、Array、Dictionary等常见类型都是结构体

所有结构都有一个编译器自动生成的初始化器(initializer,初始化方法、构造器、构造方法)

struct Point{
    var x: Int
    var y: Int
}
var p1 = Point(x: 10, y: 20)

在上树代码中我们并没有定义一个方法传入X和Y的值,编译器自动帮我们生成了这个构造方法

结构体的初始化器:

编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有成员都要有初始化值WeChat9cec8586493ce1835333c615dad95409

在x和y都没有值的情况下编译器会帮我们生成一个需要传入x,y的初始化方法

WeChate6c3be731ebcb44e0e741ab0b2ea120b

在Y有值的情况下,编译器会帮我们生成两个初始化方法

WeChatd92df0366d311bda11896adb14ab2cea

在x和y都有值的情况下,编译会帮我们生成以上四个初始化器,编译不会报错

struct Point{
    var x: Int?
    var y: Int?
}
var p1 = Point(x: 10, y: 20)
var p2 = Point(x: 10)
var p3 = Point(y: 10)
var p4 = Point()

我们编译一下代码可以得到一下结果

WeChat4527b2794af2a8e3ea7e9908ccf20fee

该代码不会报错,因为可选项有个默认值nil,结构体的所有属性都已经初始化完成,以上四个初始化器都生效

自定义初始化器

一旦在定义结构体是自定义了初始化器,编译器就不会再帮她自动生成其他初始化器WeChat4de8d558b7968dcc88ad76bc2c0c02d5

窥探初始化器的本质

struct Point{
    var x: Int = 0
    var y: Int = 0
}
var p1 = Point()
struct Point{
    var x: Int
    var y: Int
    init() {
        x = 0
        y = 0
    }
}
var p1 = Point()

以上两段代码完全等价,我们在p1的位置加个断点执行程序会到在汇编callq方法出停住,我们在控制台输入si就可以进入init的方法了,我们会看到两段代码都会进入以下汇编WeChat42e9620d3e493cc560b0fc730329ca73

发现两段汇编连内存地址都一模一样,大家可以尝试一下,说明我们自己写的初始化器和系统生成的初始化器一模一样

类的定义和结构体类似,但编译器并没有为类自动生成可以传入成员值的初始化器

如果类的所有成员都在定义的时候指定了初始值,编译器会为类生成无参的初始化器

1971640763951_.pic_hd

1981640763981_.pic_hd

查看以上两张图片,如果类内部的成员是有初始化值的,编译器会生成一个无参的初始化器,如果类内部成员没有初始化值,那么连这个无参的初始化器也不会生成成功,因为这种情况下是不安全的

结构体和类的本质区别

  • 结构体是值类型(枚举也是值类型),类是引用类型(也就是指针类型)
  • 结构体变量是在函数内部定义的那就在账上,如果是在外部定义的,那就在数据段,全局区,引用类型存储在堆空间(直接可以看汇编是否有alloc或者malloc 有就在堆,没有就在栈)
  • 值类型赋值给var、let或者给函数传参,是直接将所有内容拷贝一份;类似于对文件进行copy、paste操作,产生了全新的文件副本,属于深拷贝
  • rbp减某个值的基本就是局部变量
  • 内存地址是rip+某个值的基本就是全局变量,(程序内存 中固定死的有且只有一份内存的就是全局变量)
  • 内存地址格式为rax+某个值的,很有可能是堆空间

Lg: 在Swift标准库中,为了提升性能,String、Array、Dictionary、Set采用了copy on write

  • 比如仅当有“写”操作时,才会真正执行拷贝
  • 对于标准库值类型赋值操作,Swift能确保最佳性能,所以没必要为了保证最佳性能来避免赋值
  • 建议:不需要修改的,尽量定义成let
  • 栈空间内存地址是从高往低走,越先分配的内存地址越大

Lg:引用类型申请堆空间的过程: __allocating_init() -> swift_allocObject -> swift_slowAlloc -> malloc_zone_malloc