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,以阻止其他类从它继承。
  • 方法覆盖允许子类用新的实现替换其父类中的方法。
  • 当两个变量指向同一个类实例时,它们都指向同一块内存------改变一个变量就会改变另一个变量。
  • 类可以有一个析构函数,它是在类的实例被销毁时运行的代码。
  • 类并不像结构那样严格地强制执行常量------如果将属性声明为变量,则无论如何创建类实例,都可以更改它。
相关推荐
IT数据小能手19 分钟前
使用Go语言实现高效的数据挖掘
开发语言·golang·数据挖掘
xy1899034 分钟前
C++线程安全是如何保证的?线程不安全是如何出现的?有什么处理方案呢
开发语言·c++·安全
依旧风轻34 分钟前
232. 用栈实现队列 (Implement Queue using Stacks)
leetcode·ios·swift·queue·stack
方程式sunny37 分钟前
C#的五大设计原则-solid原则
开发语言·c#
IT数据小能手43 分钟前
PHP多线程爬虫:高效解析电商网页内容
开发语言·爬虫·php
范范08251 小时前
Symfony实战手册:PHP框架的高级应用技巧
开发语言·php·symfony
新手村领路人1 小时前
macos m2 百度paddleocr文字识别 python
开发语言·python·macos
ItKevin爱java1 小时前
java八股文面试题
java·开发语言
※※冰馨※※1 小时前
Visual Studo 2019 无法启动
开发语言·c#
宁波阿成1 小时前
基于jeecgboot-vue3的Flowable流程-集成仿钉钉流程(一)大题思路
开发语言·javascript·钉钉