说完Struct,我们再来看看Class,这应该是最经常用的了,我们还是先举例看一下怎么定义一个Class
class Person {
var firstName: String
var lastName: String
init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
var fullName: String {
return "\(firstName) \(lastName)"
}
}
let me = Person(firstName: "Joshua", lastName: "Jiang")
跟struct同样的定义Person,然后创建一个instance。从实现上来看非常像,那struct和class到底有什么区别呢?我们来更细的讨论一下。
一、Struct vs Class
1、初始方法init
不像struct会自动生成一个init让你用,上述代码中的init是必须要写的,而且和struct一样,在init中所有stored property(不懂这个的去看上一篇struct哈)都必须赋初始值。
2、Reference Type(引用类型) vs Value Type(值类型)
Struct是值类型,class是引用类型。分别是什么意思呢?
I. Value Type值类型
值类型是指当你把这种类型赋值时,整个instance是copy到被赋值的常量或变量的。Struct是值类型,之前我们说过Int, Array这些都是Struct,所以我们举一个整数的例子来了解这个概念:
var a = 3
var b = a
print("\(a), \(b)") // 3, 3
a = 10
print("\(a), \(b)") // 10. 3
可以看到b并没有因为a的改变而改变,因为把a赋值给b的时候,是把3这个值拷贝给b的。
值类型都存储在内存中的stack(栈)里,通俗一点类似这种形式:
每个变量/常量都储存了相对应的值,可以直接读取。栈里储存的数据都是程序主线程执行需要的,这些数据都被CPU很好的管理着:当你在function里创建了一个本地变量,cpu将它储存到栈里,当你的function运行结束,cpu会将它毁掉;这种机制非常有效率。
I. Reference Type引用类型
与值类型不同,当你创建并把引用类型assign给一个变量/常量时,创建的instance(实例)储存在内存中的heap(堆)里,然后在stack里,这个变量/常量储存的是一个指向heap中的instance的地址。举个栗子:
var me = Person(firstName: "Joshua", lastName: "Jiang")
var prince = me
print("\(me.firstName), \(prince.firstName)") // Joshua, Joshua
me.firstName = "coolboy"
print("\(me.firstName), \(prince.firstName)") // coolboy, coolboy
因为当把me assign给prince的时候,并没有拷贝整个instance给prince,而是拷贝了指向instance的地址;所以当me的firstName变了,那么prince的自然也会变。画个图:
画的非常通俗易懂,呵呵...
III. 判定相等or not
当你比较值类型时,不管是struct还是Int,用==即可
1 == 1 // true
当你比较引用类型时,需要用===,比较的是他们指向的地址是否相同
me === prince // true
所以虽然定义的代码看起来差不多,但struct和class还是有很大区别的!
二、常量 or 变量
我们知道如果你把一个struct复制给constant的时候,你是不能修改他的属性的;但class确可以:
struct Employee {
var jobTitle: String
}
let employee = Employee(jobTitle: "CEO")
employee.jobTitle = "CTO" // error: cannot assign to property
let me = Person(firstName: "Joshua", lastName: "Jiang")
me.firstName = "coolboy" // cool
为啥呢,因为me储存的是一个地址,我们改变instance的firstName,并没有改变me储存的那个地址。但你想改变我是什么人,那就不行了,man!
me = Person(firstName: "dog", lastName: "shit") // error: I am not
三、如何选择用Class还是Struct
Struct是用来代表值的,比如距离、名称之类的,用的时候创建不用的时候毁掉,很快的这种,你要用struct;
Class代表一个对象,像一个学生或者一个城市之类的,通常有超多的属性,一般长时间在内存里,不会随便就毁掉,这时候你当然要用class
Simple!
小QUIZ
String是引用类型还是值类型?那么下方的代码会print出什么?
var str1 = "123"
var str2 = str1
print(str1 + str2)
str1 = "abc"
print(str1 + str2)
四、Inheritance继承
class是可以继承的,虽然这是初学知识分享,但这有点儿太初学了,不多说了,栗子:
class Employee: Person {
var salary: Int = 0
func raise() {
salary += 200
}
}
class Student: Person {
var grades: Int = 0
}
let joshua = Employee(firstName: "Joshua", lastName: "J")
let ming = Student(firstName: "Ming", lastName: "Xiao")
joshua.raise() // 不需要加mutating也可以改属性的值
a) 一个class只能继承一个别的class
b) 深度不限,可以无限往下继承Person -> Employee -> President -> VP...
c) 类型转换
joshua as Person //用as要确保运行的时候会成功,不然error;一般是从子class往上cast
(joshua as? Student)?.grades // 这种情况用as?,cast不成功就return nil
(joshua as! Student).grades // 最好别用,不成功就crash
d) 如果用了final在class前面,那就不能继承了;同样func前面用了final,那么子class就不能override