苹果官方文档介绍:
Structures and Classes
Choosing Between Structures and Classes
文章中的代码基于swift5.2.4
文章目录
- 1.struct会自动生成需要的构造方法(constructor),哪个属性没有赋初始值就会生成以哪个属性为参数的构造方法。而class没有,要自己写
- 2.struct的属性可以不赋初始值,而class的属性必须赋初始值或者设为可选类型,下面也是可以的,区别只是struct自动生成了带参数的init方法
- 2.1 class遵守了协议没有实现方法会报错,而结构体(struct)不会,在正常的项目中struct也会报错,是xcode playground的问题
- 3.struct是值类型(Value Type),深拷贝。class是引用类型(Reference Type),浅拷贝。
- 4.struct不能继承,class可以继承
- 5.NSUserDefaults:Struct 不能被序列化成 NSData 对象,无法归解档
- 6.当你的项目的代码是 Swift 和 Objective-C 混合开发时,你会发现在 Objective-C 的代码里无法调用 Swift 的 Struct。因为要在 Objective-C 里调用 Swift 代码的话,对象需要继承于 NSObject。
- 7.class像oc的类一样,可以用kvo,kvc,runtime的相关方法,适用runtime系统。这些struct都不具备。
1,2
struct StructTest {
var name:String
var age:Int
}
class ClassTest {
var name:String?
var age:Int?
}
var structTest = StructTest(name: "", age: 0)
var classTest = ClassTest()
1.struct会自动生成需要的构造方法(constructor),哪个属性没有赋初始值就会生成以哪个属性为参数的构造方法。而class没有,要自己写
- 貌似如果你自己写了,系统就不会给你生成了
Memberwise Initializers for Structure Types - apple developer
2.struct的属性可以不赋初始值,而class的属性必须赋初始值或者设为可选类型,下面也是可以的,区别只是struct自动生成了带参数的init方法
class ScanInfo: NSObject {
var peripheral: CBPeripheral
var advertisementData: [String : Any]
var rssi: NSNumber
init(peripheral: CBPeripheral, advertisementData: [String : Any], rssi: NSNumber) {
self.peripheral = peripheral
self.advertisementData = advertisementData
self.rssi = rssi
}
}
2.1 class遵守了协议没有实现方法会报错,而结构体(struct)不会,在正常的项目中struct也会报错,是xcode playground的问题
3
struct StructTest {
var name:String = "struct1"
var age:Int = 0
}
class ClassTest {
var name:String = "class1"
var age:Int = 0
}
var structTest1 = StructTest()
var structTest2 = structTest1
structTest2.name = "struct2"
print("structTest1.name:\(structTest1.name)")
var classTest1 = ClassTest()
classTest1.name = "class1"
let classTest2 = classTest1
classTest2.name = "class2"
print("classTest1.name:\(classTest1.name)")
打印结果:
structTest1.name:struct1
classTest1.name:class2
3.struct是值类型(Value Type),深拷贝。class是引用类型(Reference Type),浅拷贝。
- 上面代码当classTest2.name的值变了之后,classTest1.name的值也跟着变了。而structTest1.name的值没有跟着structTest2.name的值变化
- classTest2前面用let修饰,依然可以改变classTest2.name的值。而要改变structTest2.name的值,structTest2前面必须用var
4
3.1 class中可以有单例对象属性,struct中不能有
4.struct不能继承,class可以继承
5
5.NSUserDefaults:Struct 不能被序列化成 NSData 对象,无法归解档
因为归解档的类必须遵守NSCoding协议,struct不能遵守NSCoding协议
参考:
iOS-NSUserDefaults
Swift学习记录 – Swift中throws处理方式
iOS 13归档解档
6.当你的项目的代码是 Swift 和 Objective-C 混合开发时,你会发现在 Objective-C 的代码里无法调用 Swift 的 Struct。因为要在 Objective-C 里调用 Swift 代码的话,对象需要继承于 NSObject。
7.class像oc的类一样,可以用kvo,kvc,runtime的相关方法,适用runtime系统。这些struct都不具备。
7.1 struct也不能遵守NSObjectProtocol协议
- Non-class type ‘SwiftStruct’ cannot conform to class protocol ‘NSObjectProtocol’
- Cannot declare conformance to ‘NSObjectProtocol’ in Swift; ‘SwiftClass’ should inherit ‘NSObject’ instead
8.内存分配:struct分配在栈中,class分配在堆中。struct比class更“轻量级”(struct是跑车跑得快,class是SUV可以载更多的人和货物)
知识延伸:“堆”和“栈”的区别,为什么访问struct比class块?
“堆”和“栈”并不是数据结构上的Heap跟Stack,而是程序运行中的不同内存空间。栈是程序启动的时候,系统事先分配的,使用过程中,系统不干预;堆是用的时候才向系统申请的,用完了需要交还,这个申请和交还的过程开销相对就比较大了。
栈是编译时分配空间,而堆是动态分配(运行时分配空间),所以栈的速度快。
从两方面来考虑:
1.分配和释放:堆在分配和释放时都要调用函数(MALLOC,FREE),比如分配时会到堆空间去寻找足够大小的空间(因为多次分配释放后会造成空洞),这些都会花费一定的时间,而栈却不需要这些。
2.访问时间:访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次才是真正得数据,而栈只需访问一次。
参考博客:
Swift — struct与class的差异
Swift 浅谈Struct与Class
相关参考:
查看Xcode所使用Swift的版本