美文网首页100 Days of SwiftUI
100 Days of SwiftUI - Day 10 Cla

100 Days of SwiftUI - Day 10 Cla

作者: 星星星宇 | 来源:发表于2020-10-12 17:57 被阅读0次

    Class 类

    类与结构体非常相似,我们都用它创建具有属性和方法的新数据类型。但是类引入了一个新的,重要而且复杂的功能-继承,使一个类建立在另一个类的基础上的能力。
    继承是一个强大的功能,但是请记住要使代码保持简单:功能存在,但不意味着你需要使用它。
    “任何傻瓜都可以编写计算机可以理解的代码,但是优秀的程序员可以编写人类可以理解的代码。”——Martin Fowler。
    SwiftUI中广泛使用结构体,而数据中广泛使用了类。
    与以前使用UIKit时,是非常不同的,UIKit中我们使用类进行UI设计,而使用结构体进行数据处理。

    1.创建类

    类与结构体的第一个区别就是,类中不会带有默认的成员初始化器。如果类中有属性,则必须创建自己的初始化方法。

    class Dog {
        var name: String
        var breed: String
    
        init(name: String, breed: String) {
            self.name = name
            self.breed = breed
        }
    }
    
    let poppy = Dog(name: "Poppy", breed: "Poodle")
    

    创建类的实例看起来和结构体一样。

    为什么Swift要有类和结构体?

    它们之间有五个重要的区别,后面我们详细解释这些差异。
    1.类不带有合成的成员初始化器。
    2.类可以通过继承,从而获得另一个类的属性和方法。
    3.结构体的副本始终是唯一的,而类的副本实际上指向相同的共享数据。
    4.类具有反初始化器,当类的实例被销毁时,会调用这些方法,而结构体不会。
    5.常量类中的变量属性可以自由修改,而常量结构体中的变量不能随意修改。

    2.类的继承

    类与结构体的第二个区别,就是你可以基于现有类创建另一个类,它继承了原始类的所有属性和方法,并且可以添加自己的属性和方法。
    这称为类的继承或者子类化,被继承的类称为"父类"或“超类”,新的类称为“子类”。

    基于刚才我们创建的类,我们创建一个Poodle

    class Poodle: Dog {
      init(name: String) {
            super.init(name: name, breed: "Poodle")
        }
    }
    

    因为Poodle具有自己固定的品种,所有我们提供了一个仅需要name的初始化方法。
    Swift总是要求在子类调用 super.init方法,防止父类在创建时做一些重要工作。

    为什么类不具有成员初始化器?
    因为类有继承,使得成员初始化方法很难使用,当继承一个类后,然后在子类中添加了一些属性,此时父类的成员初始化方法在子类中将不再有用,所以,Swift让我自己提供成员初始化方法。不管添加任意数量的属性,都不影响类的继承。

    3.重载 override

    子类可以用自己的实现替换父类方法。
    比如下面这个带有makeNoise()方法的普通类。

    class Dog {
        func makeNoise() {
            print("Woof!")
        }
    }
    

    我们创建一个继承的新类。通过重载override func父类方法。

    class Poodle: Dog {
        override func makeNoise() {
            print("Yip!")
        }
    }
    let poppy = Poodle()
    poppy.makeNoise()
    

    更改后,poppy.makeNoise()将打印“Yip!”。

    4.final class

    如果你不想让其他类继承你的类,你可以将类声明为final,其它类将不能继承。
    在类前添加final:

    final class Dog {
        var name: String
        var breed: String
    
        init(name: String, breed: String) {
            self.name = name
            self.breed = breed
        }
    }
    

    final以前可以带来一点点的性能提升,更重要的是final让人更容易理解你的代码。

    5. Copy

    类与结构体的第三个区别是Copy。结构体拷贝后,原始和复制的结构体是不同的,改变一个不会更改其它的结构体,而类原始副本和复制副本指向了同一个事物,因此更改一个会更改另一个。

    class Singer {
        var name = "Taylor Swift"
    }
    var singer = Singer()
    print(singer.name)
    var singerCopy = singer
    singerCopy.name = "Justin Bieber"
    print(singer.name)
    

    我们看到singer的名字已经变化。
    如果改为结构体,两次将打印相同的结果。

    为什么类要共享数据?

    类的副本共享基础数据,结构体始终具有自身的唯一数据。
    这种区别叫做“值类型与引用类型”。结构体是值类型,类时引用类型。
    结构体的值万千包含在变量内,而引用类型复制时,会获得一个新的指针,指向原始对象所在的内存。
    Swift人员更喜欢将结构体用于自定义类型,比如在一个大型程序中共享一个user对象时,如果使用的是类,有人把user数据改掉却不知道时,很可能会遇到问题。
    有时候将要共享的东西,使用类改变时并通过一些方式发送消息给其他人,可能比拷贝一些对象更好一些。

    6.Deinit

    类和结构体之间的第四个区别是,类具有反初始化,在类被销毁时运行。

    class Person {
        var name = "John Doe"
    
        init() {
            print("\(name) is alive!")
        }
    
        func printGreeting() {
            print("Hello, I'm \(name)")
        }
        deinit {
            print("\(name) is no more!")
        }
    }
    

    类为什么有deinit?

    因为类的复制行为,很难判断类何时被销毁,Swift有”自动引用计数“的操作,ARC自动跟踪类的副本,当每次获得一个副本,Swift对其引用计数+1,每次被销毁时,Swift对其引用计数中-1,计数为0时,Swift调用反初始化程序并销毁该对象。
    结构体有其自己的副本,不需要反初始化。

    7.类的Mutability

    类与结构体最终区别是,处理常量的方式。常量的结构体,属性不能更改,而类可以。
    类不需要mutating关键字。
    为什么可以更改常量类中的变量属性?

    原因在于,一个指向的是内存中的某些数据,而另一个指向值。
    结构体更改属性时,实际上是在更改整个结构。而类不会破坏并重新创建值。所以常量类可以自由更改变量属性。

    8.总结

    1.类和结构体类似,都可以使用属性和方法创建自己的类型。
    2.一个类可以从另一类继承,并获得父类所有属性和方法。
    3.final关键字标记一个类,阻止其它类继承。
    4.通过重写,子类可以使用新的实现替换父类方法。
    5.当两个变量指向同一个实例时,他们指向同一块内存。
    6.类有deinit,销毁时运行。
    7.将属性声明为变量时,无论类实例为常量或变量,都可以更改属性。

    相关文章

      网友评论

        本文标题:100 Days of SwiftUI - Day 10 Cla

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