100 Days of SwiftUI —— Day 10:类

作者: 韦弦Zhy | 来源:发表于2020-03-12 23:00 被阅读0次

    \color{red}{\Huge \mathtt{100 \ Days \ of \ SwiftUI \ — \ Day \ 10}}

    \color{orange}{\Large \mathbf{类}}

    \underline{\color{orange}{\large \mathit{Classes}}}

    最初,类看起来与结构体非常相似,因为我们使用它们来创建具有属性和方法的新数据类型。但是,它们引入了一个新的,重要的且复杂的功能,即继承——使一个类在另一个类的基础上构建的能力。

    这是一项强大的功能,毫无疑问,当您开始构建真实的iOS应用程序时,也无法避免使用类。但是请记住要保持代码简单:仅因为功能存在,并不意味着您需要使用它。正如马丁·福勒(Martin Fowler)所说,“任何傻瓜都可以编写计算机可以理解的代码,但是优秀的程序员可以编写人类可以理解的代码。(any fool can write code that a computer can understand, but good programmers write code that humans can understand.)”

    我已经说过,SwiftUI在其UI设计中广泛使用结构体。嗯,它在数据中广泛使用类:当您在屏幕上显示某个对象的数据,或者在布局之间传递数据时,通常会使用类。

    我应该补充一点:如果您以前曾经使用过UIKit,这对您来说将是一个不一样的转变——在UIKit中,我们通常使用类进行UI设计并使用结构进行数据处理。因此,如果您认为您可以在这里跳过一天,那么抱歉,您不能这样做:这是必需的。

    今天,您有8个一分钟的视频可供观看,并且您将遇到方法重写最终类反初始化器等问题。观看完每个视频后,我们会进行一次简短的测试,以帮助您了解所教的内容。

    1. 创建自己的类 Creating your own classestest

    类与结构体相似,它们使您可以使用属性和方法创建新类型,但是它们有五个重要的区别,我将逐步介绍每个区别。

    类和结构体之间的\color{red}{第一个区别}类永远不会带有成员初始化器。这意味着,如果您的类中有属性,则必须创建自己的初始化程序
    例如:

    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")
    

    2. 类继承 Class inheritancetest

    类和结构之间的\color{red}{第二个区别}是,您可以基于现有类创建一个类——它继承了原始类的所有属性和方法,并且可以在其顶部添加自己的属性。

    这称为类继承子类,您从其继承的类称为“父”或“超级”类,新类称为“子”类。

    我们刚刚创建了Dog类,我们可以基于一个名为Poodle的类创建一个新类。默认情况下,它将继承与Dog相同的属性和初始化程序:

    class Poodle: Dog {
    
    }
    

    但是,我们也可以给Poodle提供自己的初始化程序。我们知道它将始终具有品种“ Poodle”,因此我们可以创建一个仅需要name属性的新初始化程序。更好的是,我们可以使Poodle初始化程序直接调用Dog初始化程序,以便进行所有相同的设置:

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

    为了安全起见,Swift总是让您从子类中调用super.init(),以防万一父类在创建时会做一些重要的工作。

    3. 方法重写 Overriding methodstest

    子类可以使用其自己的实现替换父方法——这个过程称为重写。这是一个带有makeNoise()方法的简单Dog类:

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

    如果我们创建一个从Dog继承的新Poodle类,它将继承makeNoise()方法。因此,这将显示“ Woof!”:

    class Poodle: Dog {
    }
    
    let poppy = Poodle()
    poppy.makeNoise()
    

    方法重写允许我们更改Poodle类的makeNoise()实现。

    Swift要求我们在重写方法时使用override func而不是仅使用func——它阻止您意外重写方法,并且如果您尝试覆盖父类中不存在的内容,则会收到错误消息:

    class Poodle: Dog {
        override func makeNoise() {
            print("Yip!")
        }
    }
    

    进行此更改后,poppy.makeNoise()将显示“ Yip!”。而不是“ Woof!”。

    4. 最终类 Final classestest

    尽管类继承非常有用——实际上苹果平台的大部分都需要您使用它——有时您希望禁止其他开发人员根据您的类来构建自己的类。

    Swift为此提供了一个final关键字:当您将一个类声明为final时,其他任何类都不能从该类继承。这意味着他们无法重写您的方法来更改您的行为——他们需要以编写类的方式使用您的类。

    要使类为final,只需将final关键字放在其前面,如下所示:

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

    5. 拷贝对象 Copying objectstest

    类和结构体之间的\color{red}{第三个区别}是如何复制它们。复制结构体时,原始结构体和复制结构体都是不同的——更改一个结构体不会更改另一个结构体。复制一个类时,原始副本和复制副本都指向同一事物,因此更改一个类会同时更改另一个。

    例如,这是一个简单的Singer类,其名称属性具有默认值:

    class Singer {
        var name = "Taylor Swift"
    }
    

    如果我们创建该类的实例并打印其名称,则会得到“ Taylor Swift”:

    var singer = Singer()
    print(singer.name)
    

    现在,从第一个变量创建第二个变量,并更改其名称:

    var singerCopy = singer
    singerCopy.name = "Justin Bieber"
    

    由于类的工作方式,singersingerCopy都指向内存中的同一对象,因此当我们再次打印歌手名称时,将看到“ Justin Bieber”:

    print(singer.name)
    

    另一方面,如果Singer是结构,那么我们将第二次打印“ Taylor Swift”:

    struct Singer {
        var name = "Taylor Swift"
    }
    

    6. 反初始化器 Deinitializerstest

    类和结构之间的\color{red}{第四个区别}是类可以具有反初始化器——当类的实例被销毁时运行的代码。

    为了说明这一点,这里是一个Person类,它具有name属性,一个简单的初始化程序以及一个用于打印消息的printGreeting()方法:

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

    我们将在一个循环中创建Person类的一些实例,因为每次循环时都会创建一个新的person并销毁它:

    for _ in 1...3 {
        let person = Person()
        person.printGreeting()
    }
    

    现在来看反初始化器。当Person实例被销毁时将调用此方法:

    deinit {
        print("\(name) is no more!")
    }
    

    7. 可变性 Mutabilitytest

    类和结构体之间的\color{red}{最后的一个区别}是它们处理常量的方式。如果您具有带有可变属性的常量结构,则该属性无法更改,因为结构体本身是常量。

    但是,如果您的常量类具有可变属性,则可以更改该属性。因此,类不需要使用可更改属性的方法的mutating关键字;只有结构体才需要。

    这种差异意味着即使将类创建为常量,也可以更改类的任何变量属性——这是完全有效的代码:

    class Singer {
        var name = "Taylor Swift"
    }
    
    let taylor = Singer()
    taylor.name = "Ed Sheeran"
    print(taylor.name)
    

    如果要阻止这种情况发生,则需要使该属性为常量:

    class Singer {
        let name = "Taylor Swift"
    }
    

    8. 类:总结 Classes summarytest

    您已经完成了本系列第八部分,所以让我们总结一下:

    1、类和结构体相似,它们都可以让您使用属性和方法创建自己的类型。
    2、一个类可以从另一个类继承,并获得父类的所有属性和方法。讨论类层次结构很常见——一个类基于另一个类,而另一个类本身又基于另一个类。
    3、您可以使用final关键字标记一个类,这将阻止其他类从该类继承。
    4、通过方法重写,子类可以使用新的实现替换其父类中的方法。
    5、当两个变量指向同一类实例时,它们都指向同一块内存——改变一个会改变另一个。
    6、类可以具有一个反初始化器,该反初始化器是在销毁该类的实例时运行的代码。
    7、类对常量的强制性不如结构强——如果将属性声明为变量,则无论如何创建类实例,都可以对其进行更改。

    ╮( ̄▽ ̄)╭

    < Previous: 结构体(下) \color{orange}{\large \Bbb{100 \ Days \ of \ SwiftUI}} Next: 协议和扩展>

    相关文章

      网友评论

        本文标题:100 Days of SwiftUI —— Day 10:类

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