Swift构造器继承链

 类类型的构造器代理

Swift构造器需遵循以下三大规则:

  1. 指定构造器必须调用它直接父类的指定构造器方法
  2. 便利构造器必须调用同一个类中定义的其他初始化方法
  3. 便利构造器在最后必须调用一个指定构造器

两段式构造过程

Swift 中类的构造过程包含两个阶段。第一个阶段,类中的每个存储型属性赋一个初始值。当每个存储型属性的初始值被赋值后,第二阶段开始,它给每个类一次机会,在新实例准备使用之前进一步自定义它们的存储型属性。

两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问,也可以防止属性被另外一个构造器意外地赋予不同的值。

Swift提供了4种安全检查是开发者必须遵循的。

  1. 若子类中定义了父类没有的变量,则在子类的指定构造器中需先对该变量赋值,再调用父类的构造器。
  2. 若要在子类的指定构造器中修改继承来的变量的值,则需先调用父类的构造器。
  3. 若要在子类的便利构造器中修改任意变量的值,则需先调用同类的构造器。
  4. 所有属性被赋初始值后(即第一阶段结束后)才能调用实例方法。

阶段 1

类的某个指定构造器或便利构造器被调用。

完成类的新实例内存的分配,但此时内存还没有被初始化。

指定构造器确保其所在类引入的所有存储型属性都已赋初值。存储型属性所属的内存完成初始化。

指定构造器切换到父类的构造器,对其存储属性完成相同的任务。

这个过程沿着类的继承链一直往上执行,直到到达继承链的最顶部。

当到达了继承链最顶部,而且继承链的最后一个类已确保所有的存储型属性都已经赋值,这个实例的内存被认为已经完全初始化。此时阶段 1 完成。

阶段 2

从继承链顶部往下,继承链中每个类的指定构造器都有机会进一步自定义实例。构造器此时可以访问 self、修改它的属性并调用实例方法等等。

最终,继承链中任意的便利构造器有机会自定义实例和使用 self

构造器的继承和重写

规则:

  • 若定义的子类构造器与父类指定构造器相匹配,则需要在定义子类构造器时加上override 修饰符。
  • 若定义的子类构造器与父类便利构造器相匹配,不需要加override修饰符。
  • 若父类的指定构造器无参数,且在子类构造器中没有自定义父类的属性,那么在子类指定构造器中可以省略 super.init()
import UIKitclass lei{var name: String?init(){self.name = "123"}
}class sublei: lei{var color: Stringinit(color: String) {self.color = color//隐式调用super.init()}
}

构造器的自动继承

假设你为子类中引入的所有新属性都提供了默认值,以下 2 个规则将适用: 

规则 1: 如果子类没有定义任何指定构造器,它将自动继承父类所有的指定构造器。

import UIKitclass lei{var name: String?init(_ name: String){self.name = name}
}class sublei: lei{var color = "123"
}let a = sublei("abc")

规则 2: 如果子类提供了所有父类指定构造器的实现——无论是通过规则 1 继承过来的,还是提供了自定义实现——它将自动继承父类所有的便利构造器。 即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。

注意: 子类可以将父类的指定构造器实现为便利构造器来满足规则 2。 

import UIKitclass lei{var name: String?init(_ name: String){self.name = name}convenience init(){self.init("abc")}
}class sublei: lei{var color: String?init(_ name: String, _ color: String?){self.color = colorsuper.init(name)}convenience override init(_ name: String) {self.init(name, nil)}
}let one = sublei()

可失败构造器的重写与继承

语法:init?()

可失败构造器会创建一个类型为自身类型的可选类型的对象。你通过 return nil语句来表明可失败构造器在何种情况下应该 “失败”。

严格来说,构造器都不支持返回值。因为构造器本身的作用,只是为了确保对象能被正确构造。因此你只是用 return nil表明可失败构造器构造失败,而不要用关键字 return来表明构造成功。

重写可失败构造器可以在子类中定义一个非可失败构造器。

注意:

可以用非可失败构造器重写可失败构造器,但反过来却不行。

import UIKitclass lei{var name: String?init(){}init?(_ name: String){if name.isEmpty { return nil }self.name = name}
}class sublei: lei{override init() {super.init()self.name = "abc"}override init(_ name: String) {super.init()if name.isEmpty{self.name = "abc"}else{self.name = name}}
}

你可以在子类的不可失败构造器中使用强制解包来调用父类的可失败构造器。比如,下面的 suble子类的 name 属性的值总是 "abc",它在构造过程中使用了父类的可失败构造器 init?(name:):

class sublei: lei {
override init() {
super.init(name: "abc")!}
}

 在这个例子中,如果在调用父类的可失败构造器 init?(name:) 时传入的是空字符串,那么强制解包操作会引发运行时错误。不过,因为这里是通过字符串常量来调用它,构造器不会失败,所以并不会发生运行时错误。

必要构造器

在类的构造器前添加 required修饰符表明所有该类的子类都必须实现该构造器:

class SomeClass {required init() {// 构造器的实现代码}
}

在子类重写父类的必要构造器时,必须在子类的构造器前也添加 required修饰符,表明该构造器要求也应用于继承链后面的子类。在重写父类中必要的指定构造器时,不需要添加 override修饰符:

class SomeSubclass: SomeClass {required init() {// 构造器的实现代码}
}

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

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

相关文章

小红书广告投放形式有哪些,软文形式特点是什么?

现在广告的形式多种多样,针对不同的投放形式,面对的用户群体和投放渠道也都不一样。在平台上进行广告投放,可以快速提升品牌曝光和销量转化。本次将围绕小红书广告投放形式有哪些,软文形式特点是什么展开讨论,希望能对…

Steam搬砖上的十大网络骗术

一、buff\igxe网站api问题 骗术总结:骗子利用api链接,在网站发起报价的同时,csgo账号发起同样的报价; 解决方法:在交易网站卖完东西后,在steam注销api链接,下次使用再更换新的。交易过程中核对对…

[数据结构]-map和set

前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、键值对…

“GIF转PNG轻松转换,图片批量处理神器,提升你的图像管理效率!“

你是否曾经为转换GIF格式到PNG格式而感到困扰?或者为处理大量图片而感到烦恼?现在,我们为你推荐一款全新的GIF到PNG转换工具,以及一款图片批量处理工具,让你的图像管理工作变得轻松愉快! 首先,…

Redis安装和部署详细流程

文章目录 一、Windows环境下安装 Redis1.1 下载Redis1.2 启动redis服务器1.3 启动redis客户端1.4 配置环境变量 参考资料 一、Windows环境下安装 Redis windows系统环境下,redis安装方式主要有: zip压缩包方式 https://redis.io/download 或者 https:/…

ChatGPT生成的一些有趣的文件管理用python小程序

1. 查找当前位置中的所有文件夹,并在每个文件夹中增加一个名为 abc 的新文件夹 import osdef create_abc_directories(root_dir.):# 获取当前目录下的所有目录subdirectories [d for d in os.listdir(root_dir) if os.path.isdir(os.path.join(root_dir, d))]# 在…

vue3实现元素拖拽移动功能

效果图 实现拖拽移动 首先我们给需要实现功能的元素加一个draggable"true"让元素能够被拖拽 先来认识两个搭配draggable属性一起使用的事件——ondragstart和ondragend,它们的定义分别为: ①. ondragstart 事件在用户开始拖动元素或选择的文…

Linux安装Java环境

处理安装环境 检查系统版本 [rootjeven ~]# cat /etc/centos-release CentOS Linux release 7.6.1810 (Core)检查系统内核版本 [rootjeven ~]# uname -r 6.1.8-1.el7.elrepo.x86_64清空卸载java环境(如果已经安装了) 查询java所在位置 [rootjeven …

12.5 @ 深圳丨都说出海去接泼天的富贵,你真的准备好了吗?

今年以来,围绕“出海”的话题炙手可热。从传统企业到互联网公司,从制造业到内容产业等等,都在探索走出去的可行性。 所以我们能够看到: 在美国,打开 TikTok 看上几集中国式竖屏短剧成为了新的流行,尽管是霸…

面试篇Flink

一:为什么学习flink? 相比较spark,flink对于实时这块,使用过流的方式进行实现。 spark是通过批流的方式实现,通过减少批的时间间隔来实现流的功能。 二:什么是flink? flink是一个针对于实时进…

Vue3依赖注入

适用场景 尤其针对一个变量需要从顶层组件开始透传,途径很多个子组件最后在第n代子组件使用的时候。对于这些途经的子组件而言,它们不但不使用而且完全不关心该变量具体是什么,只是作为一个传递工具罢了。这种情况下,使用依赖注入…

Windows下搭建Tomcat HTTP服务,发布公网远程访问

文章目录 前言1.本地Tomcat网页搭建1.1 Tomcat安装1.2 配置环境变量1.3 环境配置1.4 Tomcat运行测试1.5 Cpolar安装和注册 2.本地网页发布2.1.Cpolar云端设置2.2 Cpolar本地设置 3.公网访问测试4.结语 前言 Tomcat作为一个轻量级的服务器,不仅名字很有趣&#xff0…