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 = 5422
    var 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: String
    var numberOfStoplights: Int
    var 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 = region
        self.population = population
        numberOfStoplights = 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.small
                
            case 10_001...100_000:
                return Size.medium
                
            default:
                return Size.large
            }
        }
    }
    
    enum Size {
        case small
        case medium
        case 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: String
    
    var victimPool: Int {
        get {
            return town?.population ?? 0
        }
        set(newVictimPool) {
            town?.population = newVictimPool
        }
    }
    
    //自定义的初始化方法, required 表示所有子类都必须实现此构造方法,否则程序会报错
    required init(town: Town?, monsterName: String) {
        self.town = town
        name = 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: Bool
    private(set) var isFallingApart: Bool
    
    //子类特有的初始化方法
    init(limp: Bool, fallingApart: Bool, town: Town?, monsterName: String) {
        walksWithLimp = limp
        isFallingApart = fallingApart
        super.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 = false
        isFallingApart = false
        super.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.")
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3 命名实体识别调优化

能走到这里说明你对模型微调有了一个基本的认识。那么开始一段命名实体的任务过程,下面使用huggingface官网的数据。 1 准备模型 下面的模型自己选择一个吧,我的内存太第一个模型跑不了。 https://huggingface.co/ckiplab/bert-base-chinese-ner/tree…

在vscode上面进行分支merge的记录

前言:在我们的项目中,有两个分支:master和liutielong。现在要将liutielong分支的改动merge到master分支中。 如果master分支已经更改了,所以要先pull(这是在git bash里面的命令)。 git pull origin master…

HTML5+CSS3小实例:炫彩荧光线条登录框

实例:炫彩荧光线条登录框 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-sca…

【网络安全】对称加密、非对称加密以及密钥分配

目录 1、对称加密 2、非对称加密 3、如何分配对称密钥&#xff1f; 4、如何分配非对称密钥&#xff1f; 1、对称加密 所谓对称加密&#xff0c;就是指加密密钥与解密密钥都使用相同的密钥。如下图所示&#xff0c;通信双方使用的就是对称加密密钥。//代表&#xff1a;DES和…

【数据库】MongoDB

文章目录 [toc]数据库操作查询数据库切换数据库查询当前数据库删除数据库查询数据库版本 数据集合操作创建数据集合查询数据集合删除数据集合 数据插入插入id重复的数据 数据更新数据更新一条丢失其他字段保留其他字段 数据批量更新 数据删除数据删除一条数据批量删除 数据查询…

如何启用启用WordPress调试模式

最近我们的WordPress网站在访问时&#xff0c;经常出现打不开的现象&#xff0c;我们向主机提供商Hostease咨询后&#xff0c;他们提到这是由于WordPress的某个插件导致的问题&#xff0c;我们在将插件版本升级至最新后&#xff0c;这个问题就消失了。为了方便后续的检查&#…

【VI/VIM】基本操作备忘录

简介 新建/打开文件 工作模式 常用命令 补全命令 命令模式输入&#xff1a;ctrl p 移动命令 文本选中 撤销、删除 复制粘贴 替换 缩排 查找 替换 插入 分屏 练习

react引入iconfont的svg图标

react引入iconfont的svg图标 本文目录 react引入iconfont的svg图标普通图标通过link引入css组件内引入css使用 svg图标通过script引入js组件内引入js使用 通过封装组件自定义封装组件中调用 通过antd封装使用 普通图标 通过link引入css <link rel"stylesheet" h…

setTimeout回调函数 this指向问题

本文主要介绍setTimeout的回调函数的this指向问题 例子1&#xff1a;回调函数是一个普通函数 setTimeout 的回调函数是一个普通函数&#xff0c;而不是箭头函数&#xff0c;因此它有自己的上下文&#xff0c;this 指向全局对象&#xff08;在浏览器中是 window 对象&#xff…

MySQL创建数据库与表

要求&#xff1a; 1.在本机安装数据库 2.创建一个数据库db_classes 3.创建一行表db_hero 4.将四大名著中的常见人物插入这个英雄表 目录 要求&#xff1a; 过程&#xff1a; 结果&#xff1a; 命令总结&#xff1a; 过程&#xff1a; 1.安装数据库 http://t.csdnimg…

QML 不同风格和主题的切换

Quick程序提供了方便的用于切换不同风格和主题的配置文件&#xff0c;如果没有设计稿&#xff0c;又想界面没那么丑&#xff0c;那么可以用这套配置&#xff0c;让应用看起来相对专业一点。 一&#xff0c;在 qrc 资源文件中添加 qtquickcontrols2.conf 文件。 二&#xff0c;…

iOS - 多线程的安全隐患

文章目录 iOS - 多线程的安全隐患1. 卖票案例2. 多线程安全隐患的解决方案2.1 iOS中的线程同步方案2.2 同步方案的使用2.2.1 OSSpinLock2.2.1.1 使用方法&#xff1a;2.2.1.2 案例 2.2.2 os_unfair_lock2.2.2.1 使用方法&#xff1a;2.2.2.2 案例 2.2.3 pthread_mutex2.2.3.1 使…

uniapp APP检测更新

需求&#xff1a; 1.首次进入APP给出弹窗提示是否存在最新版本APP&#xff0c;可选择更新或者取消 2.选择取消后&#xff0c;在使用期间不再弹出该弹窗 3.在设置中增加按钮&#xff0c;点击进行版本检测&#xff0c;再弹窗 效果图&#xff1a; 使用到的插件&#xff1a;APP升…

“三三裂变”,实体书营销实操细节分享……

“三三裂变”实操细节 一、实验结果 “三三裂变”的实验,结果比较好。就是我们大概有300人报名,但实际行动的只有109人,大概有103人都完成了三个人的目标,也就是说我们通过109人裂变了475人,利润率是1:4.5左右,整个裂变的效率还是可以的,也就是说: 如果你用这种方法有…

3节点ubuntu24.04服务器docker-compose方式部署高可用elk+kafka日志系统并接入nginx日志

一&#xff1a;系统版本: 二&#xff1a;部署环境&#xff1a; 节点名称 IP 部署组件及版本 配置文件路径 机器CPU 机器内存 机器存储 Log-001 10.10.100.1 zookeeper:3.4.13 kafka:2.8.1 elasticsearch:7.7.0 logstash:7.7.0 kibana:7.7.0 zookeeper:/data/zookeep…

微服务项目实战-黑马头条(八):App端-文章ES搜索、MongoDB搜索记录和关键词联想

文章目录 一、今日内容介绍1.1 App端搜索-效果图1.2 今日内容 二、搭建ElasticSearch环境2.1 拉取镜像2.2 创建容器2.3 配置中文分词器 ik2.4 使用postman测试 三、app端文章搜索3.1 需求分析3.2 思路分析3.3 创建索引和映射3.4 数据初始化到索引库3.4.1 导入es-init到heima-le…

JS -正则表达式

正则表达式 关于正则表达式&#xff0c;其实我写过几篇了&#xff0c;但是真正的正则表达式其实主要用于定义一些字符串的规则&#xff0c;计算机根据给出的正则表达式&#xff0c;来检查一个字符串是否符合规则。 我们来看一下&#xff0c;在JS中如何创建正则表达式对象。 语…

HTML:PC和手机的自适应图形布局样例

作者:私语茶馆 1.前言 有时我们需要开发一个自适应PC和手机的HTML页面,由于屏幕大小不同,会涉及到自动部署。W3School提供了一个非常好的案例:Responsive Image Gallery。本文利用独立CSS文件详细介绍一下这个案例。 2.案例详细介绍 2.1.Project项目文件结构 企业级项目…

电脑问题快速判断

电脑开机没有任何反应 检查电源 检查电源是否有问题或损坏&#xff0c;可以短接方法检测 板电源卡口对自己接第四或第五根线&#xff0c;若风扇匀速转动&#xff0c;电源无问题&#xff0c;若不转动或转一下停一下&#xff0c;电源有问题 检查内部连线 确保主板上的线插的…

Docker常用命令(镜像、容器、网络)

一、镜像 1.1 存出镜像 将镜像保存成为本地文件 格式&#xff1a;docker save -o 存储文件名 存储的镜像docker save -o nginx nginx:latest 1.2 载入镜像 将镜像文件导入到镜像库中 格式&#xff1a;docker load < 存出的文件或docker load -i 存出的文件…