IOS Swift 从入门到精通: 类和继承

文章目录

创建自己的类

类与结构类似,因为它们允许您创建具有属性和方法的新类型,但它们有五个重要的区别,我将逐一介绍每个区别。

类和结构体之间的第一个区别是,类从不带有成员初始化器。这意味着如果你的类中有属性,你必须始终创建自己的初始化器。

例如:

swift 复制代码
class Dog {
    var name: String
    var breed: String

    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

创建该类的实例看起来与创建结构体一样:

swift 复制代码
let poppy = Dog(name: "Poppy", breed: "Poodle")

类继承

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

这称为类继承或子类化,继承的类称为"父"类或"超"类,新类称为"子"类。

这是Dog我们刚刚创建的类:

swift 复制代码
class Dog {
    var name: String
    var breed: String

    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

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

swift 复制代码
class Poodle: Dog {

}

但是,我们也可以为其提供Poodle自己的初始化程序。我们知道它的品种永远是"贵宾犬",因此我们可以创建一个只需要name属性的新初始化程序。甚至更好的是,我们可以让Poodle初始化程序直接调用Dog初始化程序,这样所有相同的设置都会发生:

swift 复制代码
class Poodle: Dog {
    init(name: String) {
        super.init(name: name, breed: "Poodle")
    }
}

出于安全原因,Swift 总是让你从子类中调用super.init()------以防父类在创建时做一些重要的工作。

覆盖方法

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

swift 复制代码
class Dog {
    func makeNoise() {
        print("Woof!")
    }
}

如果我们创建一个Poodle继承自 的新类Dog,它将继承该makeNoise()方法。因此,这将打印"Woof!":

swift 复制代码
class Poodle: Dog {
}

let poppy = Poodle()
poppy.makeNoise()

方法覆盖允许我们改变类的makeNoise()实现Poodle。

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

swift 复制代码
class Poodle: Dog {
    override func makeNoise() {
        print("Yip!")
    }
}

经过这一改变,poppy.makeNoise()将打印"Yip!"而不是"Woof!"。

final 类

尽管类继承非常有用 - 而且事实上 Apple 的大部分平台都要求您使用它 - 但有时您想禁止其他开发人员基于您的类构建他们自己的类。

Swift 为我们提供了一个final关键字,目的就是:当你将一个类声明为 final 时,其他类就不能继承它。这意味着他们不能重写你的方法以改变你的行为------他们需要按照编写的方式使用你的类。

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

swift 复制代码
final class Dog {
    var name: String
    var breed: String

    init(name: String, breed: String) {
        self.name = name
        self.breed = breed
    }
}

复制对象

类和结构之间的第三个区别在于它们如何被复制。复制结构时,原始结构和副本都是不同的东西------更改其中一个不会更改另一个。复制类时,原始结构和副本都指向同一个东西,因此更改其中一个会更改另一个。

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

swift 复制代码
class Singer {
    var name = "Taylor Swift"
}

如果我们创建该类的一个实例并打印其名称,我们将得到"Taylor Swift":

swift 复制代码
var singer = Singer()
print(singer.name)

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

swift 复制代码
var singerCopy = singer
singerCopy.name = "Justin Bieber"

由于类的工作方式,singer和都singerCopy指向内存中的同一个对象,所以当我们再次打印歌手名字时,我们会看到"Justin Bieber":

swift 复制代码
print(singer.name)

另一方面,如果Singer是一个结构体,那么我们会第二次打印"Taylor Swift":

swift 复制代码
struct Singer {
    var name = "Taylor Swift"
}

反初始化器

类和结构之间的第四个区别是,类可以有反初始化程序------当类的实例被销毁时运行的代码。

为了演示这一点,这里有一个具有属性、简单初始化程序和打印消息的方法的Person类:

swift 复制代码
nameprintGreeting()

class Person {
    var name = "John Doe"

    init() {
        print("\(name) is alive!")
    }

    func printGreeting() {
        print("Hello, I'm \(name)")
    }
}

我们将Person在循环内创建该类的几个实例,因为每次循环都会创建一个新的人,然后销毁:

swift 复制代码
for _ in 1...3 {
    let person = Person()
    person.printGreeting()
}

Person现在来看看析构函数。当实例被销毁时,它将被调用:

swift 复制代码
deinit {
    print("\(name) is no more!")
}

可变性

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

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

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

swift 复制代码
class Singer {
    var name = "Taylor Swift"
}

let taylor = Singer()
taylor.name = "Ed Sheeran"
print(taylor.name)

如果您想阻止这种情况发生,您需要使该属性保持不变:

swift 复制代码
class Singer {
    let name = "Taylor Swift"
}

总结

让我们总结一下:

  • 类和结构类似,因为它们都可以让你创建具有属性和方法的自己的类型。
  • 一个类可以继承另一个类,并获得父类的所有属性和方法。我们经常讨论类层次结构------一个类基于另一个类,而另一个类又基于另一个类。
  • 你可以用关键字标记一个类final,以阻止其他类从它继承。
  • 方法覆盖允许子类用新的实现替换其父类中的方法。
  • 当两个变量指向同一个类实例时,它们都指向同一块内存------改变一个变量就会改变另一个变量。
  • 类可以有一个析构函数,它是在类的实例被销毁时运行的代码。
  • 类并不像结构那样严格地强制执行常量------如果将属性声明为变量,则无论如何创建类实例,都可以更改它。
相关推荐
湫ccc31 分钟前
《Python基础》之字符串格式化输出
开发语言·python
mqiqe1 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin1 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
Ysjt | 深2 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
ephemerals__2 小时前
【c++丨STL】list模拟实现(附源码)
开发语言·c++·list
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货2 小时前
Rust 的简介
开发语言·后端·rust
湫ccc2 小时前
《Python基础》之基本数据类型
开发语言·python