Swift初学 - 四大自定义数据类型之Class

2019-10-11  本文已影响0人  Joshua666

说完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(栈)里,通俗一点类似这种形式:


heap.png

每个变量/常量都储存了相对应的值,可以直接读取。栈里储存的数据都是程序主线程执行需要的,这些数据都被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的自然也会变。画个图:


class.png

画的非常通俗易懂,呵呵...

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

上一篇下一篇

猜你喜欢

热点阅读