Swift 【Class】【struct】

1.定义

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

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

SwiftObject

在swift中,如果没有明确声明父类的类,则会隐式地继承自 SwiftObject (支持与 Objective-C 混编的前提下,因为 SwiftObject 是一个 Objective-C 类),隐式继承来源于 swift 的 ABI/TypeLayout.rst 文档。

SwiftObject 的声明是 SWIFT_OBJC_INTEROP 为 true 的情况下才有声明的,而在苹果平台下,都是支持 swift 与 Objective-C 进行混编的,因此 SWIFT_OBJC_INTEROP 为 1(true)SWIFT_OBJC_INTEROP 宏的定义可在 Config.h 中找到

从 SwiftObject 的定义中可以看到

  • 第一个成员变量和 Objective-C 一样是 isa 指针,暂时猜想和 Objective-C 中的 isa 指针功能一样
  • 第二个成员变量是一个 SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS 宏,其定义可在 HeapObject.h 和 RefCount.h中找到,从命名上看是引用计数器

2.区别

2.1.类是引用类型,结构体是值类型。

值类型在传递和赋值时将进行复制,而引用类型则只会使用引用对象的一个指向。引用类型是在堆上,而值类型是在栈上进行存储和操作。相比栈上的操作,对上的操作更加复杂耗时,所以苹果官方推荐使用结构体,这样可以提高App运行的效率。值类型赋值给let var 或者函数传参的时候全是深拷贝;引用类型赋值给let var 或者函数传参的时候完,是将内存地址拷贝一份,属于浅拷贝。结构体属于值类型,标准库中的结构体采用copy on write策略,优化效率;

2.2.class有这几个功能struct没有的:

class可以继承,这样子类可以使用父类的特性和方法。
类型转换可以在runtime的时候检查和解释一个实例的类型。
可以用deinit来释放资源。
一个类可以被多次引用。


2.3.结构体不可以继承,可以继承;

2.4.结构体初始化的时候必须要给属性赋值,来决定结构体在内存中的布局.Class初始化的时候可以暂时不用赋值;


2.5.都可以实现方法,都可以添加计算属性和存储属性,都支持属性监听,都支持扩展.都可以遵守协议;


2.6.required关键字只支持Class, Class可以用static和Class 关键字修饰静态方法;Struct 只能用Static 修饰;

2.7,类一定是分配在堆空间上,结构体可能分配在堆空间:比如类中的结构体属性,栈空间:比如声明在方法中,数据段:声明为全局变量

2.8类,有析构函数。结构体不能有析构函数。

2.9.结构体构造函数会自动生成带参数的构造器。类不会对有初始化赋值生成带参数的构造器。

2.10.类有继承特性,结构体没有继承特性。结构体无继承特性,则无法对成员属性、成员方法、类属性、类方法进行重载。结构体的函数操作符需要static,不能使用class。

2.11.类中的每一个成员变量都必须被初始化,否则编译器会报错。而结构体不需要,编译器会自动帮我们生成init函数,给变量赋一个默认值。

2.12.类中可以有单例,结构体不能有

2.13NSUserDefaults:结构体不能序列化成NSDate,无法归档。类可以

2.14.混合开发时,oc中不能调用swift中的结构体

2.15.方法派发:

• 静态派发:编译器讲函数地址直接编码在汇编中,调用的时候根据地址直接跳转到实现,编译器可以进行内联等优化,Struct都是静态派发。

•动态派发:运行时查找函数表,找到后再跳转到实现,动态派发仅仅多一个查表环节并不是他慢的原因,真正的原因是它阻止了编译器可以进行的内联等优化手段

2.16.struct在func里面需要修改property的时候需要加上mutating关键字,而class就不用。

3.相同点

3.1定义存储值的属性
3.2定义方法
3.3定义下标以使用下标语法提供对其值的访问
3.4定义初始化器
3.5使用 extension 来拓展功能
3.6遵循协议来提供某种功能

3.7.范型

3.8协议采纳

4.观察器

4.结构体的内存结构

struct Point {
    var x: Int = 0
    var y: Int = 0
}

print(MemoryLayout<Point>.size)   // 16
print(MemoryLayout<Point>.stride) // 16
print(MemoryLayout<Point>.alignment) // 8

通过打印可知结构体Point实际占用16字节,总占用16字节,内存对齐为8字节。
这很好理解,因为两个存储属性x和y都是Int类型,都是占用8字节,所以实际占用16字节。

struct Point {
    var x: Int = 0
    var y: Int = 0
    var b: Bool = true
}

print(MemoryLayout<Point>.size)   // 17
print(MemoryLayout<Point>.stride) // 24
print(MemoryLayout<Point>.alignment) // 8

这里Point实际占用17字节,因为存储属性x是Int型占用8字节,y是Int型占用8字节,b是Bool型占用1字节。
内存对齐为8字节,所以总占用是8+8+8=24字节。

5.如何选择

5.1、 堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些。

5.2、 结构表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存。在此情况下,结构的成本较低。

5.3、 在表现抽象和多级别的对象层次时,类是最好的选择。

5.4、 大多数情况下该类型只是一些数据时,结构时最佳的选择。

5.5、结构体的主要目的是为了封装一些相关的简单数据值。

5.6、当你在赋予或者传递结构实例时,有理由需要封装的数据值被拷贝而不是引用。

5.7、任何存储在结构体中的属性是值类型,也将被拷贝而不是被引用。

5.8、结构体不需要从一个已存在类型继承属性或者行为。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值