Swift-27-类的初始化与销毁

Swift的初始化是一个有大量规则的固定过程。初始化是设置类型实例的操作,包括给每个存储属性初始值,以及一些其他准备工作。完成这个过程后,实例就可以使用了。 简单来讲就是类的构造函数,基本语法如下:

注意:初始化不仅只针对类,也对结构体有效。类和结构体通用
在这里插入图片描述

对象初始化函数定义

类的初始化

init是关键字,参数个数0~N个,这个是和Objective-C语言是有点不太一样的。

 class CustomType {init(someValue: SomeType) { //init是关键字,参数个数0~N个// 初始化代码}
}

如果不显示声明初始化函数的话,默认为init(){}。

结构体初始化

默认初始化函数

swift为结构体提供了两种默认的构造函数,一种是空属性的,另一种是全属性的。所以像下面的代码两种调用方式都可以。

//Town.swift
struct Town { //定义了一个名为Town的结构体//定义了两个属性var population = 5422var numberOfStoplights = 4//定义实例方法func printDescription() {print("Population: \(population); number of stop lights: \(numberOfStoplights)")}//定义修改方法,需要添加mutating关键字mutating func changePopulation(by amount: Int) {population += amount}
}

测试代码

var town = Town()
var town = Town(population:10000, numberOfStoplights:10)

自定义初始化函数

如果自定义了构造函数,上述两种默认构造函数就全不能用了。

struct Town {//因为删除了默认值,所以不能和自动类型识别了,需要手动指定属性类型let region: Stringvar numberOfStoplights: Intvar population: Int {didSet(oldPopulation) {print("The population has changed to \(population) from \(oldPopulation).")}}/*下面是自定义的初始化方法,这里的?号表示可失败的初始化方法也可以用!号来代替,也可以不写1.可失败的意思一般用于参数检查,如果检查失败则返回一个nil值。然后在程序调用时也用myTown?这种方式调用,会更安全;2. guard 就是一个关键字,用于确保可以提前返回*/init?(region: String, population: Int, stoplights: Int) {//可失败就体现在这里,参数如果不合适,则直接返回nil(创建失改),这种特性比较好用,在其它语言中一种会用抛异常的方式或工厂的方式来实现。guard population > 0 else {return nil}self.region = regionself.population = populationnumberOfStoplights = stoplights}//初始化方法2:N/A表示空字符串值传入init?(population: Int, stoplights: Int) {self.init(region: "N/A", population: population, stoplights: stoplights)}var townSize: Size {get {precondition(self.population >= 0, "Town cannot have negative population.")switch self.population {case 0...10_000:return Size.smallcase 10_001...100_000:return Size.mediumdefault:return Size.large}}}enum Size {case smallcase mediumcase large}func printDescription() {print("Population: \(population); number of stop lights: \(numberOfStoplights); region: \(region)")}mutating func changePopulation(_ amount: Int) {population += amount}
}

测试调用

var myTown = Town(population: 5, stoplights: 4)
myTown?.printDescription()let ts = myTown?.townSize
print(ts) //Optional(swiftcommandtool.Town.Size.small)

对象初始化

类的初始化需要注意继承的问题,默认时类只会提供一个空的构造函数方法,这是和结构体不一样的地方

  1. 指定初始化方法,用于给类的所有属性设置初始值;程序代码没有任何修饰关键字,可以有多个;
  2. 便捷初始化方法,只是一种标识,一般会委托给指定初始化方法来实现;用关键字convenience修饰,可以有多个;
  3. 类的必需初始化方法,一个类要求其子类必须提供特定的初始化方法;
  4. 反初始化方法,在类的实例销毁时执行内存清理过程;用deinit定义,一个类只能有一个此方法

因为默认的初始化方法必须给所有属性设置初始值,则便捷初始化方法则不需要。

默认初始化方法

类的默认初始化方法也是int(){},与结构体不同,类没有默认的成员初始化方法。这解释了为什么之前要给类设置默认值:这样可以利用自带的空初始化方法。比如:let fredTheZombie = Zombie(),其中的空圆括号表示这是一个默认初始化方法。

自定义构造函数

父类

class Monster {var town: Town?var name: Stringvar victimPool: Int {get {return town?.population ?? 0}set(newVictimPool) {town?.population = newVictimPool}}//自定义的初始化方法, required 表示所有子类都必须实现此构造方法,否则程序会报错required init(town: Town?, monsterName: String) {self.town = townname = monsterName}func terrorizeTown() {if town != nil {print("\(name) is terrorizing a town!")} else {print("\(name) hasn't found a town to terrorize yet...")}}
}

子类

默认情况下子类不会自动继承父类的初始化方法,目的是希望避免子类在不经意间提供了无法为所有属性赋值的初始化方法,但在下列两种场景中子类会继承父类的初始化方法:

  1. 子类没有定义任何自定义的初始化方法;
  2. 如果子类复写了父类所有指定的初始化方法,也会继承父类的所有便捷初始化方法;
class Zombie: Monster {class var spookyNoise: String {return "Brains..."}var walksWithLimp: Boolprivate(set) var isFallingApart: Bool//子类特有的初始化方法init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {walksWithLimp = limpisFallingApart = fallingApartsuper.init(town: town, monsterName: monsterName)}//convenience 关键字用来表示快捷初始化方法convenience init(limp: Bool, fallingApart: Bool) {self.init(limp: limp, fallingApart: fallingApart, town: nil, monsterName: "Fred")if walksWithLimp {print("This zombie has a bad knee.")}}//复写父类的初始化方法,可以省略overrid关键字required init(town: Town?, monsterName: String) {walksWithLimp = falseisFallingApart = falsesuper.init(town: town, monsterName: monsterName) //调用父类构造函数}final override func terrorizeTown() {if !isFallingApart {town?.changePopulation(-10)}}}

程序调用

//调用Zombie指定初始化方法:init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) 
//The population has changed to 999995 from 1000005.
//Population: 999995; number of stop lights: 4; region: N/A
var fredTheZombie: Zombie? = Zombie(limp: false, fallingApart: false, town: myTown, monsterName: "Fred")
fredTheZombie?.terrorizeTown()
fredTheZombie?.town?.printDescription()//调用快捷初始化方法:convenience init(limp: Bool, fallingApart: Bool)
//This zombie has a bad knee.
var convenientZombie = Zombie(limp: true, fallingApart: false)//Victim pool: Optional(999995)
//The population has changed to 500 from 999995.
//Victim pool: Optional(500)
print("Victim pool: \(fredTheZombie?.victimPool)")
fredTheZombie?.victimPool = 500
print("Victim pool: \(fredTheZombie?.victimPool)")//调用反初始化方法
//Brains...
//Zombie named Fred is no longer with us.
print(Zombie.spookyNoise)
fredTheZombie = nil

初始化函数参数

初始化的函数参数也和普通函数一样,支持内、外名称加类型这种,也支持一些特殊特性,比如下面的_用法,隐藏外部参数名称。

struct WeightRecordInLBS {let weight: Double//用_来指定init(_ pounds: Double) {weight = pounds}init(kilograms kilos: Double) {weight = kilos * 2.20462} 
}//
let wr = WeightRecordInLBS(185)

对象的销毁(反向初始化)

反初始化(deinitialization)是在类的实例没用之后将其清除出内存的过程。从概念上讲,反初始化就是初始化的反面。只有引用类型可以反初始化,值类型不行。 在Swift中,实例被清除出内存之前会调用反初始化方法。这提供了销毁实例前最后做一些维 护工作的机会。

    deinit {print("Zombie named \(name) is no longer with us.")}

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

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

相关文章

C语言扫雷游戏完整实现(上)

文章目录 前言一、新建好头文件和源文件二、实现游戏菜单选择功能三、定义游戏函数四、初始化棋盘五、 打印棋盘函数六、布置雷函数七、玩家排雷菜单八、标记功能的菜单九、标记功能菜单的实现总结 前言 C语言从新建文件到游戏菜单,游戏函数,初始化棋盘…

JavaScript-4.正则表达式、BOM

正则表达式 正则表达式包含在"/","/"中 开始与结束 ^ 字符串的开始 $ 字符串的结束 例: "^The":表示所有以"The"开始的字符串("There"、"The cat"等&#x…

数据结构(八)——排序

八、排序 8.1 排序的基本概念 排序(Sort),就是重新排列表中的元素,使表少的元素满足按关键字有序的过程。 输入∶n个记录R1,R2...., Rn,对应的关键字为k1, k2,... , kn 输出:输入序列的一个重排R1,R2....,Rn,使得有k1≤k2≤...≤…

综合大实验

题目: 1、R4为ISP,其上只配置IP地址;R4与其他所直连设备间均使用公有IP; 2、R3-R5、R6、R7为MGRE环境,R3为中心站点; 3、整个OSPF环境IP基于172.16.0.0/16划分;除了R12有两个环回,其…

VUE父组件向子组件传递值

创作灵感 最近在写一个项目时,遇到了这样的一个需求。我封装了一个组件,这个组件需要被以下两个地方使用,一个是搜索用户时用到,一个是修改用户信息时需要用到。其中,在搜索用户时,可以根据姓名或者账号进…

OllyDbg 快捷键及常用法

keywords: debug, ollydbg 快捷键 Ctrl --> C Shift --> S Alt --> M 功能快捷键设置/取消断点F2执行到光标所在行F4步过F8步进F7运行F9暂停F12回到应用层M-F9打开文件F3重新调试C-F2打开应用程序输入表C-n寻找表达式C-g打开断点窗口M-b切换断点状态空格添加备注…

[前端]NVM管理器安装、nodejs、npm、yarn配置

NVM管理器安装、nodejs、npm、yarn配置 NVM管理器安装 nvm(Node.js version manager) 是一个命令行应用,可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 nvm下载地址:https://github.com/coreybutler/nvm-windows/releases 1.全部…

Unity面向切面编程

一直说面向AOP(切面)编程,好久直接专门扒出理论、代码学习过。最近因为某些原因😭还得再学学造火箭的技术。 废话不多说,啥是AOP呢?这里我就不班门弄斧了,网上资料一大堆,解释的肯定…

mybatis中<if>条件判断带数字的字符串失效问题

文章目录 一、项目背景二、真实错误原因说明三、解决方案3.1针对纯数字的字符串值场景3.2针对单个字符的字符串值场景 四、参考文献 一、项目背景 MySQL数据库使用Mybatis查询拼接select语句中进行<if>条件拼接的时候&#xff0c;发现带数字的或者带单个字母的字符串失效…

CPU资源控制

一、CPU资源控制定义 cgroups&#xff08;control groups&#xff09;是一个非常强大的linux内核工具&#xff0c;他不仅可以限制被namespace隔离起来的资源&#xff0c; 还可以为资源设置权重、计算使用量、操控进程启停等等。 所以cgroups&#xff08;control groups&#xf…

在ubuntu20上编译bcc时遇到:Could NOT find LibDebuginfod

参考&#xff1a;https://github.com/iovisor/bcc/issues/3601 环境 Ubuntu20.04 ARM64 问题 编译bcc时报下面的错误&#xff1a; -- Found BISON: /usr/bin/bison (found version "3.5.1") -- Found FLEX: /usr/bin/flex (found version "2.6.4") …

Netty学习——实战篇5 Netty 心跳监测/WebSocket长连接编程 备份

1 心跳监测 MyServer.java public class MyServer {public static void main(String[] args) {NioEventLoopGroup bossGroup new NioEventLoopGroup(1);NioEventLoopGroup workerGroup new NioEventLoopGroup();try {ServerBootstrap serverBootstrap new ServerBootstrap…

leetcode145--二叉树的后序遍历

1. 题意 求后序遍历 2. 题解 2.1 递归 class Solution { public:void addPost(TreeNode *root, vector<int> &res) {if ( nullptr root)return ;addPost(root->left, res);addPost(root->right, res);res.emplace_back( root->val );}vector<int>…

设计前后端系统以处理长时间运行的计算任务并提供缓存支持

后端设计 1. 任务队列 创建一个任务队列来存储提交的计算任务。 Component public class TaskQueue {private final Queue<CalculationTask> queue new LinkedList<>();public synchronized void addTask(CalculationTask task) {queue.add(task);}public sync…

C++ 全量枚举

在C中&#xff0c;全量枚举通常指的是为一个类型的所有可能值创建一个枚举。这样可以使代码更具可读性&#xff0c;特别是当你需要处理有限的、固定的值集合时。 下面是一个简单的例子&#xff0c;展示了如何定义和使用枚举&#xff1a; #include <iostream>// 定义枚举…

lvresize与lvextend扩容逻辑卷的区别

这两条命令都是用来扩展逻辑卷&#xff08;Logical Volume&#xff09;的命令&#xff0c;但是有一些区别&#xff1a; 1. lvresize命令&#xff1a; - lvresize命令是用来调整逻辑卷的大小的&#xff0c;可以缩小或扩大逻辑卷的大小。 - 在使用lvresize命令时&#xff0c;需…

20240425 每日一题:2739. 总行驶距离

题目简介 卡车有两个油箱。给你两个整数&#xff0c;mainTank 表示主油箱中的燃料&#xff08;以升为单位&#xff09;&#xff0c;additionalTank 表示副油箱中的燃料&#xff08;以升为单位&#xff09;。 该卡车每耗费 1 升燃料都可以行驶 10 km。每当主油箱使用了 5 升燃…

学习Docker笔记

在23号刚刚学完新版本的docker还想说回去继续学习老版本的springcloud课程里面的docker 结果一看黑马首页新版本课程出了&#xff0c;绷不住了。以下是我学习新版本docker的笔记&#xff0c;记录了我学习过程遇到的各种bug和解决&#xff0c;也参考了黑马老师的笔记&#xff1a…

TDengine高可用探讨

提到数据库&#xff0c;不可避免的要考虑高可用HA&#xff08;High Availability&#xff09;。但是很多人对高可用的理解并不是很透彻。 要搞清高可用需要回答以下几个问题&#xff1a; 什么是高可用&#xff1f;为什么需要高可用&#xff1f;高可用需要达到什么样的目标&am…

Unity射线实现碰撞检测(不需要rigbody组件)

使用physic.CapsulCast&#xff08;&#xff09;&#xff1b; 前面3个参数生成一个胶囊体&#xff0c; 向着发射方向&#xff0c;发射出一串的胶囊&#xff08;没有最大距离&#xff09; 有最大距离&#xff0c;可以节约性能开销。 physic.CapsulCast&#xff08;&#xff0…