Swift学习(七):结构体、类与枚举的异同(初始化器,值类型,引用类型)

结构体

  • 在 Swift 标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分 
  • 比如Bool、Int、Double、 String、Array、Dictionary等常见类型都是结构体

 

  • 在第6行调用的,可以传入所有成员值,用以初始化所有成员(存储属性,Stored Property)

结构体的初始化器

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

  

上面的Point在声明时没有为先x, y初始化值,p1给x和y赋值了,p2,p3,p4没有为x,y赋全值

 x有初始化值,y没有初始化值

y有初始化值,x没有初始化值

  x,y都有初始化值

  • 下面的代码能编译通过吗?

 因为可选项都有个默认值nil,因此可以编译通过


结构体的初始化器

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

  这时不会默认初始化值,需要传入,否则报错

 

  • 以下两段代码完全等效

      

  • 结构体的内存结构


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

由上可得:类的属性一定要有初始化值

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

  • 上面2段代码是完全等效的

结构体与类的本质区别

结构体是值类型(枚举也是值类型),类是引用类型(指针类型)

由上可以看出:point也就是结构体存储在栈空间,size也就是类存储在堆空间

上图都是针对64bit环境


值类型

  • 值类型赋值给var、let或者给函数传参,是直接将所有内容拷贝一份, 类似于对文件进行copy、paste操作,产生了全新的文件副本。属于深拷贝(deep copy)

 由于是值类型,互不影响,所以p1.x = 10, p1.y = 20


值类型的赋值

   

  • 在Swift标准库中,为了提升性能,String、Array、Dictionary、Set采取了Copy On Write的技术 
  • 比如仅当有“写”操作时,才会真正执行拷贝操作
  • 对于标准库值类型的赋值操作,Swift 能确保最佳性能,所有没必要为了保证最佳性能来避免赋值
  • Swift标准库中的结构体为保持性能,只有在结构体被赋值并且有写入的时候才进行深拷贝,但是自己定义的结构体,只要结构体有被赋值操作就会深拷贝。
  • 建议:不需要修改的,尽量定义成let


引用类型

  • 引用赋值给var、let或者给函数传参,是将内存地址拷贝一份
  • 类似于制作一个文件的替身(快捷方式、链接),指向的是同一个文件。属于浅拷贝(shallow copy)

  

 属于浅拷贝,s1.width = 11, s2.height  = 22


对象的堆空间的申请过程

  •  在Swift中,创建类的实例对象,要向堆空间申请内存,大概流程如下
  • Class.__allocating_init()
  • libswiftCore.dylib:_swift_allocObject_
  • libswiftCore.dylib:swift_slowAlloc
  • libsystem_malloc.dylib:malloc
  • 在Mac、iOS中的malloc函数分配的内存大小总是16的倍数
  • 通过class_getInstanceSize可以得知类的对象真正使用的内存大小

具体解析内存占用:

import Foundation

func testInstance() {
    class Point {
        //引用类型前面会有16个字节
        var x : Int = 11  //8
        var test = true  //1
        var y : Int = 22 //8
    }
    let p = Point()
    print(class_getInstanceSize(Point.self)) //40
    print(class_getInstanceSize(type(of: p))) //40
    print(Mems.size(ofRef:p)) //48
    //33   类对象真正利用,真正存具体数据的内存空间
    //40   类的对象真正使用的内存大小
    //48   类对象实际分配的内存大小
}

 


引用类型的赋值操作

 


值类型、引用类型的let

   

p表示值类型赋值的内存数据是常量,不可变,也就是10和20不可变,下面对p的三个赋值操作都改变了栈空间的内存数据,所以报错

s表示引用类型赋值的内存数据是常量,这里的栈空间存储的内存数据是指向堆内存空间的地址,第一个属于重新赋一个新值,指向的内存地址改变,所以报错,但是后两个没有改变指向的堆内存的地址,所以没有报错

  


嵌套类型


枚举、类、结构体都可以定义方法

一般把定义在枚举、结构体、类内部的函数,叫做方法

枚举:

类: 

结构体: 

注意;方法不占用实力对象内存的,方法的本质就是函数,方法实际上是放在代码段的.

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值