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

文章目录

  • 创建自己的类
  • 类继承
  • 覆盖方法
  • final 类
  • 复制对象
  • 反初始化器
  • 可变性
  • 总结

创建自己的类

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

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

例如:

class Dog {var name: Stringvar breed: Stringinit(name: String, breed: String) {self.name = nameself.breed = breed}
}

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

let poppy = Dog(name: "Poppy", breed: "Poodle")

类继承

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

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

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

class Dog {var name: Stringvar breed: Stringinit(name: String, breed: String) {self.name = nameself.breed = breed}
}

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

class Poodle: Dog {}

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

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

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

覆盖方法

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

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

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

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

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

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

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

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

final 类

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

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

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

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

复制对象

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

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

class Singer {var name = "Taylor Swift"
}

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

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

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

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

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

print(singer.name)

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

struct Singer {var name = "Taylor Swift"
}

反初始化器

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

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

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

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

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

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

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

可变性

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

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

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

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

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

class Singer {let name = "Taylor Swift"
}

总结

让我们总结一下:

  • 类和结构类似,因为它们都可以让你创建具有属性和方法的自己的类型。
  • 一个类可以继承另一个类,并获得父类的所有属性和方法。我们经常讨论类层次结构——一个类基于另一个类,而另一个类又基于另一个类。
  • 你可以用关键字标记一个类final,以阻止其他类从它继承。
  • 方法覆盖允许子类用新的实现替换其父类中的方法。
  • 当两个变量指向同一个类实例时,它们都指向同一块内存——改变一个变量就会改变另一个变量。
  • 类可以有一个析构函数,它是在类的实例被销毁时运行的代码。
  • 类并不像结构那样严格地强制执行常量——如果将属性声明为变量,则无论如何创建类实例,都可以更改它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/32216.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

速度测试分析软件MySpeed

什么是 MySpeed ? MySpeed 是一款速度测试分析软件,可记录您长达 30 天的互联网速度。使用 MySpeed,您可以轻松生成有关速度、ping 等的清晰统计数据。配置运行状况检查,以便在出现错误或停机时通过 Gotify、Discord、WhatsApp 或…

海报设计师的福音来了,微软联合清华北大提出Glyph-ByT5-v2,可支持多国语言图文海报生成,效果惊艳!

清华&北大&微软&利物浦大学联合提出Glyph-ByT5-v2这款工具支持多语言图文生成,包括英语、中文、日文、韩文、法文、德文、西班牙文、意大利文、葡萄牙文和俄文。 以下分别展示中、英、日、韩图文的视觉文本结果一起带大家感受一下。 相关链接 论文地址…

Linux源码阅读笔记03-调度器及CFS调度器

调度器 调度器:Linux内核中用来安排调度进程(一段程序的执行过程)执行的模块成为调度器,他可以切换进程状态。比如:执行、可中断睡眠、不可中断睡眠、退出、暂停等; 调度器的主要职责:选择某些…

gbase8s关于客户端和数据库连接的方式和应用建立连接的简单线索分工

应用和数据库的连接分为本地连接和远程连接,当应用程序和数据库在同一台服务器上为本地连接,不在一台服务器上为远程连接 1. 本地连接 本地连接三种方式: 通过共享内存消息系统:应用和数据库在同一台服务器上,应用程…

判别式模型 vs 生成式模型

判别式模型 vs 生成式模型 在机器学习中,判别式模型和生成式模型是两种重要的模型类型。让我们用简单的语言来理解它们的原理、特点和应用场景。 判别式模型(Discriminative Model) 什么是判别式模型? 判别式模型专注于区分类别…

C语言 | Leetcode C语言题解之第165题比较版本号

题目&#xff1a; 题解&#xff1a; int compareVersion(char * version1, char * version2){int len1 strlen(version1);int len2 strlen(version2);int i 0;int j 0;while (i < len1 || j < len2) {int num1 0;int num2 0;while (i < len1 && versio…

C#实现音乐在线播放和下载——Windows程序设计作业3

1. 作业内容 编写一个C#程序&#xff0c;在作业二实现的本地播放功能的基础上&#xff0c;新增在线播放和在线下载功能&#xff0c;作业二博客地址&#xff1a;C#实现简单音乐文件解析播放——Windows程序设计作业2 2. 架构选择 考虑到需求中的界面友好和跨版本兼容性&#xf…

【ThreeJS】Threejs +Vue3 开发基础

目前流行的前端3D框架以以Three.js、Babylon.js、A-Frame和ThingJS为例&#xff1a; 1.Three.js 功能&#xff1a; 提供了大量的3D功能&#xff0c;包括基本几何形状、材质、灯光、动画、特效等。 易用性&#xff1a; 功能强大且易于使用&#xff0c;抽象了复杂的底层细节&…

题解:P3569 [POI2014] KAR-Cards

题意 有 n n n 个元素&#xff0c;第 i i i 个元素有两个权值 a i a_i ai​ 和 b i b_i bi​&#xff1b;有 m m m 次操作&#xff0c;每次操作会交换两个元素的位置&#xff0c;且都需要回答&#xff1a;是否存在一种方案&#xff0c;使得每个元素各选择一个权值后&#…

STM32读取芯片内部温度

基于stm32f103cbt6这款芯片&#xff0c;原理部分请参考其他文章&#xff0c;此文章为快速上手得到结果&#xff0c;以结果为导向。 1.基础配置 打开stm32cubemx只需要勾选中 ADC1 Temperature Sensor Channel 2.代码分析 /** 函数名&#xff1a;float GetAdcAnlogValue(voi…

120.网络游戏逆向分析与漏洞攻防-邮件系统数据分析-邮件发送功能的封装

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

【前端面试】理解 JavaScript 中的 Set 和 Map 对象

目录 一、Set 对象1. 基本操作2. 遍历操作3. Set 的特性4. 与数组的互操作 二、Map 对象1. 基本操作2. 遍历操作3. Map 的特性4. 与对象的比较 三、算法题及题解题目&#xff1a;找出数组中的重复元素题目&#xff1a;数组去重题目&#xff1a;统计字符串中每个字符出现的次数题…

简单的 Python Web 应用 Docker 化案例

简单的 Python Web 应用 Docker 化案例 在这个案例中&#xff0c;我们将展示如何使用 Docker 容器化一个简单的 Python Web 应用。我们将创建一个基于 Flask 框架的 Hello World 应用&#xff0c;并使用 Docker 和 Docker Compose 管理容器化环境。 1. 创建 Python Web 应用 …

STM32项目分享:家庭环境监测系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.…

集群初始配置

假设已经有三台或多台 Linux&#xff0c;可以是虚拟机或真实设备。如果希望使用这些 Linux 组成一个集群&#xff0c;并在上面运行一些分布式系统&#xff0c;可能需要如下操作。 1 设置静态IP 输入命令route -n打印路由表&#xff0c;可以查看网关地址。图形界面操作&#x…

跌倒识别:守护公共安全的AI技术应用场景-免费API调用

随着科技的不断进步&#xff0c;人工智能在各个领域的应用日益广泛&#xff0c;其中在公共安全领域&#xff0c;智能跌倒识别系统正逐渐成为守护人们安全的重要工具。本文将分享智能跌倒识别系统在不同场景下的应用及其重要性。 产品在线体验地址-API调用或本地化部署 AI算法模…

【Golang - 90天从新手到大师】Day02 - 基本语法

系列文章合集 Golang - 90天从新手到大师 变量和常量 变量声明 标准声明 var name type批量声明 var (name1 type1name2 type2... )声明时初始化 var name type value类型推导 var name value短变量声明 name : value匿名声明 在使用多重赋值时&#xff0c;如果想要…

【第一性原理】邓巴数字

这里写自定义目录标题 什么是邓巴数字邓巴数背后的科学历史上各个组织的人数与邓巴数字的关系在人类进化中的意义现代社会中邓巴数字的体现邓巴数字的意义其他与沟通相关的数据注意事项结论参考 罗宾邓巴教授生于1947年&#xff0c;进化心理学家&#xff0c;牛津大学教授&#…

[信号与系统]关于LTI系统的转换方程、拉普拉斯变换和z变换

前言 本文还是作为前置知识。 LTI系统的传递函数 LTI系统的传递函数 H ( z ) H(z) H(z) 是输出信号的z变换 Y ( z ) Y(z) Y(z) 与输入信号的z变换 X ( z ) X(z) X(z) 的比值&#xff1a; H ( z ) Y ( z ) X ( z ) H(z) \frac{Y(z)}{X(z)} H(z)X(z)Y(z)​ 多项式比值表…

C++之提高篇

1.标准输入输出流 cin与cout的使用&#xff0c;就不多说了&#xff0c;说一个有关保留小数位数的操作&#xff0c;使用ostream对象的precision&#xff08;&#xff09;方法&#xff0c;表达的意思是数字总共有几位&#xff0c;注意&#xff0c;此时是包括整数部分的&#xff…