必须知道的
- 共同点
a.定义存储属性
b.定义函数
c.定义下标,使用下表访问自己的值
d.定义初始化设置自己的初始化状态
e.扩展自己的功能
f.实现协议提供某种特定的标准功能 - 不同点(类有更多功能)
a.类可以继承,结构体不能继承
b.类能够在运行时检查和解释类实例的类型
c.Deinitializers使一个类的实例来释放任何资源分配
d.类有引用计数,允许对象被多次引用
验证
- 定义
// 定义类
class StudentC{
}
// 定义结构体
struct StudentS{
}
- 定义存储属性
// 定义类
class StudentC{
var name:String!
}
// 定义结构体
struct StudentS{
var name:String
}
提示:
在类中定义属性必须要注意,如果你定义的存储属性不是可选值类型,必须进行初始化,不然编译会报错,但是结构体不会报错,因为系统默认会给结构体创建初始化方法
- 定义函数
// 定义类
class StudentC{
static var des:String = "学生的类"
var name:String!
func getName()->String{
return name
}
class func describe()->String{
return des
}
static func getClassDescribe()->String{
return des
}
}
// 定义结构体
struct StudentS{
static var des:String = "学生的结构体"
var name:String
static func describe()->String{
return "这是一个定义学生的类"
}
}
提示:
类可以使用关键字static class 修饰方法,但是结构体只能使用关键字static修饰
- 扩展下标
class StudentC{
var names:[String] = ["1","2","3","4","5"]
subscript (index:Int)->String?{
get{
if names.count <= index{
return nil
}
return names[index]
}
}
}
// 定义结构体
struct StudentS{
var names:[String] = ["1","2","3","4","5"]
subscript (index:Int)->String?{
get{
if names.count <= index{
return nil
}
return names[index]
}
}
}
// 执行
let student1 = StudentC()
print(student1[8])
- 初始化
// 定义类
class StudentC{
var name:String
init( name:String) {
self.name = name
}
}
// 定义结构体
struct StudentS{
var name:String
init(name:String) {
self.name = name
}
}
let student1 = StudentC(name: "酷走天涯")
let student2 = StudentS(name: "XUJIE")
提示:
结构体默认会有初始化方法
struct StudentS{
var name:String
}
let student2 = StudentS(name: "xujie")
- 扩展功能
extension StudentC{
func describe()->String{
return "学生" + self.name
}
}
extension StudentS{
func describe()->String{
return "学生" + self.name
}
}
- 实现协议
// 定义一个协议
protocol Capacity{
func draw() // 协议方法
}
// 定义类
class StudentC:Capacity{
// 实现协议方法
internal func draw() {
}
var name:String
init( name:String) {
self.name = name
}
}
// 定义结构体
struct StudentS:Capacity{
// 实现协议方法
internal func draw() {
}
var name:String
}
- 继承
// 定义基类
class Person{
var name:String
init( name:String) {
self.name = name
}
}
// 定义类
class StudentC:Person{
var score:Float
init( name:String,score:Float) {
self.score = score
super.init(name: name)
self.name = name
}
}
提示:
结构体不能继承结构体
- mutating 关键字的作用
结构体和枚举都是值类型,但是默认值类型的对象方法不能修改属性值,但是要修改怎么办呢?就必须在函数前面加mutating
//例子1
protocol Action{
var myY:Int{ mutating get}
}
struct Point{
var x:Int
var y:Int
// 结构体或者枚举修改值必须在函数前面加mutating
mutating func modifyX(x:Int){
self.x = x
}
// 注意计算属性,mutating 要加载getter方法前面
var myY:Int{
mutating get {
self.y = self.y*2
return y
}
}
}
// 例子2
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
// 例子3
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
提示:
1.计算属性setter方法不用修改属性值不用添加mutating
2.计算属性setter方法中修改属性值的时候,一定要加mutating
- 检测两个对象地址是不是相同
class StudentC{
var name:String
init( name:String) {
self.name = name
}
}
let student1 = StudentC(name: "xujie")
let student2 = student1
if student1 === student2{
print("地址相同")
}
运行结果:
地址相同
结论:
类是引用类型,结构体是值类型,不能使用===/!== 判断地址
测试:
// 定义结构体
struct StudentS{
var name:String
}
let student1 = StudentS(name: "xujie")
var student2 = student1
student2.name = "酷走天涯"
print(student1.name)
print(student2.name)
运行结果:
xujie
酷走天涯
- Deinitializers使一个类的实例来释放任何资源分配
// 定义类
class StudentC{
var name:String
init( name:String) {
self.name = name
}
deinit {
// 释放资源
}
}
提示:
结构体没有deinit 方法
高级话题
a. 什么时候用结构体
1.该结构的主要目的是封装几个相对简单的数据值
2.如果你希望你的结构在传递的时候被赋值而不是引用
3.希望结构在传递的时候,内部的属性也被复制而不是引用
4.不需要继承属性或者方法
主要应用场景(只包含非对象类型)
1.定义Size
2.定义范围Range
3.定义坐标XYZ
...
b.什么时候用类
除了上面的场景外,其余都使用类对象。
官方建议:
define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures.
用性能说话
测试1: 循环创建类和结构体
a.执行1亿次类创建
// 定义类
class StudentC{
var name:String
init( name:String) {
self.name = name
}
}
// 统计时间
let date = Date()
for i in 0...100_000_000{
let s = StudentC(name: "酷走天涯")
}
print(Date().timeIntervalSince(date))
运行三次结果:
13.3261250257492
13.3587710261345
13.2861340045929
b.执行10亿次结构体创建
// 定义结构体
struct StudentS{
var name:String
init( name:String) {
self.name = name
}
}
let date = Date()
for i in 0...1000_000_000{
let s = StudentS(name: "酷走天涯")
}
print(Date().timeIntervalSince(date))
运行三次结果:
6.93744301795959
7.18747901916504
7.20444202423096
我们上面的属性为基本数据类型,我们将属性改为对象测试一下速度
c.创建10_000_000个对象
class StudentC{
var date = NSDate()
}
for i in 0...10_000_000{
let s = StudentS()
}
测试结果:
3.38509398698807
3.4364920258522
3.39519000053406
d.创建10_000_000个结构体实例
struct StudentS{
var date = NSDate()
}
for i in 0...10_000_000{
let s = StudentS()
}
测试结果:
2.04776203632355
2.03975200653076
1.98246997594833
结论:
创建结构体要比创建对象速度快
测试2:创建1000_000 个对象或者结构体放在数组中,查看内存占用率
a.循环创建1000_000个对象
class StudentC{
var name:String
init( name:String) {
self.name = name
}
}
var students:[StudentC] = []
// 创建
for i in 0...1000_000{
let s = StudentC(name: "酷走天涯")
students.append(s)
}
运行结果:
内存占用61.8MB
b.循环创建1000_000个结构体
struct StudentS{
var name:String
init( name:String) {
self.name = name
}
}
var students:[StudentS] = []
for i in 0...1000_000{
let s = StudentS(name: "酷走天涯")
students.append(s)
}
运行结果:
内存占用32.6MB
照样,我们将基本属性改为对象继续测试
c.10_000_000 个对象添加到数组中
class StudentC{
var date = NSDate()
}
var students:[StudentC] = []
for i in 0...10_000_000{
let s = StudentC()
students.append(s)
}
测试结果:
占内存538.7MB
d.10_000_000 个结构体添加到数组中
struct StudentS{
var date = NSDate()
}
for i in 0...10_000_000{
let s = StudentS()
students.append(s)
}
测试结构:
占用225.7MB
结论:
创建相同属性的结构体比类更加节省内存
- 对1_000_000个结构体实体和对象进行排序,测消耗时间
a.对1_000_000个结构体实体进行排序
let date = Date()
students.sort { (stu1, stu2) -> Bool in
return stu1.name > stu2.name
}
print(Date().timeIntervalSince(date))
运行结果:
13.3783949613571
13.6793909668922
b.对1_000_000个对象进行排序
let date = Date()
students.sort { (stu1, stu2) -> Bool in
return stu1.name > stu2.name
}
print(Date().timeIntervalSince(date))
运行结果:
6.70881998538971
6.60394102334976
结论: 在数据量比较大的排序中,结构体排序的速度比较慢,因为结构体是值类型,排序的时候,需要大量的赋值运算。而对象只需要交换地址即可。
综合建议:
结构体创建速度,内存占用更小,如果需要使用复杂的运算,这个时候,就需要综合考虑两者的有缺点了。