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、结构体不需要从一个已存在类型继承属性或者行为。
|