美文网首页
Swift初学 - 四大自定义数据类型之Class

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

作者: Joshua666 | 来源:发表于2019-10-11 13:55 被阅读0次

    说完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

    相关文章

      网友评论

          本文标题:Swift初学 - 四大自定义数据类型之Class

          本文链接:https://www.haomeiwen.com/subject/zmetmctx.html