Swift中的init方法
摘要:Swift有着超级严格的初始化方法,不仅强化了designated初始化方法的地位,所有不加修饰的init方法都需要在方法中确保非Optional的实例变量被赋值初始化,而在子类中,也强制调用super版本的designated初始化。
我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的。
其实就是安全。在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误。
所以Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都需要在方法中保证所有非Optional的实例变量被赋值初始化,而在子类中也强制 (显式或隐式地)调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。
- class ClassA {
- let numA: Int
- init(num: Int) {
- numA = num
- }
- }
- class ClassB: ClassA {
- let numB: Int
- override init(num: Int) {
- numB = num + 1
- super.init(num: num)
- }
- }
在上面的示例代码中,注意在init里我们可以对let的实例常量进行赋值,这是初始化方法的重要特点。在Swift中let声明的值是不变量,无法被写入赋值,这对于构建线程安全的API十分有用。而因为Swift的init只可能被调用一次,因此在init中我们可以为不变量进行赋值,而不会引起任何线程安全的问题。
与designated初始化方法对应的是在init前加上convenience关键字的初始化方法。这类方法是Swift初始化方法中的“二等公民”,只作为补充和提供使用上的方便。所有的convenience初始化方法都必须调用同一个类中的designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。
- class ClassA {
- let numA: Int
- init(num: Int) {
- numA = num
- }
- convenience init(bigNum: Bool) {
- self.init(num: bigNum ? 10000 : 1)
- }
- }
- class ClassB: ClassA {
- let numB: Int
- override init(num: Int) {
- numB = num + 1
- super.init(num: num)
- }
- }
只要在子类中实现重写了父类convenience方法所需要的init方法的话,我们在子类中就也可以使用父类的convenience初始化方法了。比如在上面的代码中,我们在ClassB里实现了init(num: Int)的重写。这样,即使在ClassB中没有bigNum版本的convenience init(bigNum: Bool),我们仍然还是可以用这个方法来完成子类初始化:
- let anObj = ClassB(bigNum: true)
- // anObj.numA = 10000, anObj.numB = 10001
因此进行一下总结,可以看到初始化方法永远遵循以下两个原则:
- 初始化路径必须保证对象完全初始化,这可以通过调用本类型的designated初始化方法来得到保证;
- 子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。
对于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样的一个最大的好处是可以保证依赖于某个designated初始化方法的convenience一直可以被使用。一个现成的例子就是上面的init(bigNum: Bool):如果我们希望这个初始化方法对于子类一定可用,那么应当将init(num: Int)声明为必须,这样我们在子类中调用init(bigNum: Bool)时就始终能够找到一条完全初始化的路径了:
- class ClassA {
- let numA: Int
- required init(num: Int) {
- numA = num
- }
- convenience init(bigNum: Bool) {
- self.init(num: bigNum ? 10000 : 1)
- }
- }
- class ClassB: ClassA {
- let numB: Int
- required init(num: Int) {
- numB = num + 1
- super.init(num: num)
- }
- }
另外需要说明的是,其实不仅仅是对designated初始化方法,对于convenience的初始化方法,我们也可以加上required以确保子类对其进行实现。这在要求子类不直接使用父类中的convenience初始化方法时会非常有帮助。
Swift中的init方法的更多相关文章
- Swift基础--Swift中的分类以及在分类中扩展init方法的注意事项
Swift中的分类 1.创建一个空的swift文件 2.关键字extension,格式: extension 要扩展的类名 {} extension UIButton { } Swift中扩展init ...
- IOS开发中重写init方法使用需谨慎
IOS开发中重写init方法使用需谨慎 今天在写一个小软件的时候出现一点问题,这个软件的功能是搜索全国学校,首页就是搜索输入框,在框中输入完要查询的学校所在省份,点击buttom后就会跳转到对应的视图 ...
- iOS开发之swift与OC混编出现的坑,oc中不能对swift的代理进行调用,不能访问swift中的代理,swift中的回调方法
1. Swift与oc混编译具体怎么实现,这儿我就不重复讲出了,网上有大把的人讲解. 2. 在swift与OC混编的编译环境下, oc类不能访问swift创建类中的代理? 解决方法如下: 在代理的头部 ...
- Swift基础之init方法,实例方法,类方法(静态方法)的使用(多标签Demo)
Xcode更新过后,有些方法都进行了改变,Demo中有变化的都进行了简单的标记,具体以后遇见再说 创建一个UIView类,用init方法创建两种类型,显示多标签,创建静态方法进行调用,创建类方法进行调 ...
- OC中自定义init方法
---恢复内容开始--- 我们知道,在函数中实例化一个对象,大多数会同时进行初始化,如 Person *p =[ [Person alloc]init]; 此时已经进行了初始化,使用init方法,那么 ...
- Swift新手教程系列5-函数+selector在swift中的使用方法
原创blog.转载请注明出处 近期在用swift写代码,尽管遇到一些问题,可是代码量确实减了不少. swfit新手教程系列会随着我使用swfit中的积累,不断地去修正更新 之前的教程 swift单例模 ...
- Swift中自定义打印方法
// 1.获取打印所在的文件 let file = ( #file as NSString).lastPathComponent // 2.获取打印所在的方法 let funcName = #func ...
- python中的Init方法, new 方法 call 方法
new 方法实现单列模式思考 class Single: _single = None _single_only = None def __init__(self, value): self.v = ...
- python 子类中定义init方法
随机推荐
- NYOJ4——ASCII码排序
ASCII码排序 时间限制:3000 ms | 内存限制:65535 KB 难度:2 描述:输入三个字符(可以重复)后,按各字符的ASCII码从小到大的顺序输出这三个字符. 输入:第一行输入一 ...
- vector刘汝佳算法入门学习笔记
//*****-*-----vector***/////// 常用操作封装,a.size();可以读取大小 a.resize();可以改变大小: ...
- mysql关于时间函数的应用
1.获取今天的数据 date_format(publishtime, '%Y-%m-%d')= date_format(now(), '%Y-%m-%d') 2.获取今天和明天的数据 server.b ...
- 合作网络(Corporative Network )并查集+路径压缩
#include <iostream> #include <algorithm> #include <string> using namespace std; + ...
- hdu 5409 CRB and Graph(边双联通分量)
题意: 给一个图一些边,保证图连通 问对于每条边,如果去除该边后使得图中一些点不连通.设这些点(u,v),要求使u尽量小,v尽量大,输出这样的(u,v).否则输出0 0. #include <b ...
- HBuilder mui 报错No 'Access-Control-Allow-Origin' header
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' he ...
- 贪心+拓扑排序 AOJ 2456 Usoperanto
题目传送门 题意:给出一条链,比如x连到y,x一定要在y的左边,且代价是这条链经过的点的权值和,问如何排序使得代价最小 分析:类似拓扑排序,先把入度为0的点入队,把指向该点的所有点按照权值排序,保证这 ...
- sql基础语法-联接查询
交叉联接 1.不带where条件的,将返回两个表的 行乘积 select c.*, e.* from Sales.Customers c cross join hr.Employees e 2.带wh ...
- java中stringBuilder的用法
java中stringBuilder的用法 String对象是不可改变的.每次使用 System.String类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间.在需 ...
- Suricata的配置
见官网 https://suricata.readthedocs.io/en/latest/configuration/index.html# Docs » 8. Configuration Edit ...