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