本篇主要讲解 Swift 中 Designated、Convenience和 Required 的使用:

  在 OC 中 init 方法是非常不安全的,没人能够保证 init 只被调用一次,也没有人保证在初始化方法调用以后实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的的话,还可能会造成各种问题。Swift 强化了 designated 初始化方法的地位。swift 中不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化,而在子类中也强制(显示或隐式的)调用 super 版本的 designated 初始化,所以无论怎样被初始化的对象总是可以完成完整的初始化的。

class ClassA {
let numA: Int
init(num: Int) { // 不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化
numA = num
}
} class ClassB: ClassA {
let numB: Int
override init(num: Int) {
numB = num + // 在 init 里我们可以对 let 的实例常量进行赋值,这是初始化方法的重要特点。正常情况下 let 声明的值是不可变的,无法被赋值,这对构建线程安全的 API 十分有用。而 init 只可能被调用一次,所以在 init 里我们可以为不变量进行赋值,而不会引起任何线程安全的问题
super.init(num: num)
}
}

  与 designated 初始化方法啊对应的是在 init 前加上 convenience 关键字的初始化方法。这类方法只作为补充和提供使用上的方便。所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置,另外 convenience 的初始化方法是不能被子类重写或者是从子类中以 super 的方式被调用的。

class ClassAA {
let numA: Int
init(num: Int) {
numA = num
}
convenience init(bigNum: Bool) {
self.init(num: bigNum ? : ) // 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置
}
} class ClassBB: ClassAA {
let numB: Int
override init(num: Int) {
numB = num +
super.init(num: num)
}
}

  只要在子类中实现重写了父类 convenience 方法所需要的 init 方法的话,我们在子类中就可以使用父类的 convenience 初始化方法了。比如上面我们及时在 ClassBB 中没有 bigNum 版本的 convenience init(bigNum: Bool),我们仍然是可以是用这个方法来完成子类初始化的:

let anObj = ClassBB(bigNum: true)
print(anObj.numA, anObj.numB)

输出结果:

总结:初始化方法永远遵循以下两个原则

1.初始化路径必须保证对象完全初始化,这可以通过调用本类型的 designated 初始化方法得到保证;

2.子类的 designated 初始化方法必须调用父类的 designated 方法,以保证父类也完成初始化。

  对于某些我们希望子类中一定实现的 designated 初始化方法,我们可以通过添加 required 关键字进行限制,强制子类对这个方法重写实现。这样做的最大的好处是可以保证依赖于某个 designated 初始化方法的 convenience 一直可以被使用。

下面的代码中如果希望初始化方法对于子类一定可用,就将 init(num: Int) 声明为必须。

class ClassAAA {
let numA: Int
required init(num: Int) {
numA = num
}
required convenience init(bigNum: Bool) {
self.init(num: bigNum ? : )
} }
class ClassBBB: ClassAAA {
let numB: Int
required init(num: Int) {
numB = num +
super.init(num: num)
}
}
let sencondObj = ClassBB(bigNum: true)
print(sencondObj.numA, sencondObj.numB)

输出结果:

对于 convenience 的初始化方法我们也可以加上 required 以确保子类对其进行实现。

Swift开发第十一篇——Designated、Convenience和Required的更多相关文章

  1. Swift开发第十篇——可变参数函数&初始化方法顺序

    本篇分为两部分: 一.Swift中的可变参数函数 二.初始化方法的顺序 一.Swift中的可变参数函数 可变参数函数指的是可以接受任意多个参数的函数,在 OC 中,拼接字符串的函数就属于可变参数函数 ...

  2. Swift开发第八篇——方法嵌套&命名空间

    本篇分为两部分: 一.Swift中的方法嵌套 二.Swift中的命名空间 一.Swift中的方法嵌套 在 swift 中我们可以让方法嵌套方法,如: func appendQuery(var url: ...

  3. Swift开发第七篇——字面量转换&下标

    本篇分为两部分: 一.Swift 中的字面量转换 二.Swift 中的下标 一.Swift 中的字面量转换 所谓字面量就是指像特定的数字,字符串或者是布尔值这样能够直接了当地指出自己的类型并未变量进行 ...

  4. Swift开发第六篇——操作运算符也可以重载& func 的参数修饰

    本篇分为两部分: 1.Swift 中重载操作运算符的使用 2.Swfit 中 func 的参数修饰 1.Swift 中重载操作运算符的使用 与别的语言不同,Swift 支持运算符的重载,运算符指的是“ ...

  5. Swift开发第五篇——四个知识点(Struct Mutable方法&Tuple&autoclosure&Optional Chain)

    本篇分三部分: 一.Struct Mutable方法 二.多元组(Tuple) 的使用 三.autoclosure 的使用 四.Optional Chain 的使用 一.Struct Mutable方 ...

  6. Swift开发第四篇——柯里化

    本篇分为两部分: 一.柯里化的基本使用 二.柯里化的使用场景 一.柯里化的基本使用 柯里化(Currying):也就是把接受多个参数的方法变换成接受第一个参数的方法,并且返回接受余下的参数并且返回结果 ...

  7. Swift开发第三篇——Playground

    本篇分为两部分: 一.Playground的延时运行 二.Playground的可视化 一.Playground的延时运行 Playground 就是提供一个可以即时编译的类似 REPL 的环境,他为 ...

  8. PowerBI开发 第十一篇:报表设计技巧(更新)

    PowerBI版本在持续的更新,这使得报表设计能够实现更多新的功能,您可以访问 PowerBI Blog查看PowerBI的最新更新信息,本文总结了PowerBI新版本的重要更新和设计技巧. 我的Po ...

  9. swift开发多线程篇 - 多线程基础

    swift开发多线程篇 - 多线程基础 iOS 的三种多线程技术 (1)NSThread  使用NSThread对象建立一个线程非常方便 但是!要使用NSThread管理多个线程非常困难,不推荐使用 ...

随机推荐

  1. [锋利JQ]-图片提示效果

    新知识点: 在HTML-Dom中 "style" 属性,是所有HTML标签共有的一个对象属性,这个对象属性可以为元素设置内嵌样式. style是元素的属性,但是它自身则是一个对象, ...

  2. Autofac - 服务

    上一篇中, 留了一个小问题,在一个接口下面, 注册多个类, 并能正常获取. 之前的方式是不能做到的, 在服务中, 有一种实现方式是可以的. 一.服务 1. 类型 - 描述服务的基本方法 上一篇其实使用 ...

  3. ASP.NET MVC处理JsonResult返回时间DateTime问题

    在开发ASP.NET MVC时,如果你有使用jQuery的Ajax去获取一些json数据时,其中数据返回有包含日期时间的话,也许会觉得有点小问题. 现针对此问题,写一个小例子来演示一下,创建一个控制器 ...

  4. 如何在Web项目中给没有添加API核心组件添加APIController的帮助页HelpPage

    前言: ASP.NET中的Web项目可以通过APIController控制器来为其他项目提供接口.  而我们在调试这些接口时,可以选择单元测试,网页测试(Get接口),自己写测试代码或者第三方测试工具 ...

  5. [水煮 ASP.NET Web API2 方法论](3-6)万能路由

    问题 定义什么样的路由,可以不会受请求参数类型和数量的限制,而被全部捕获? 解决方案 在路由模板中,给参数添加一个"*"前缀,例如 {*param},只要请求的 URL 能够和路由 ...

  6. SSH服务器与Android通信(1)--服务器端发送数据

    很多应用要求SSH服务器不仅和PC通信,还要和Android移动设备通信,这时就需要用到JSON了.其基本原理是服务器将数据转换成JSON格式,发送给Android客户端,客户端再将JSON格式的数据 ...

  7. Type mismatch: cannot convert from java.sql.PreparedStatement to com.mysql.jdbc.PreparedStatement

    Connection.prepareStatement()函数出错,提示: Type mismatch: cannot convert from java.sql.PreparedStatement ...

  8. Eclipse导入Java项目时“No projects are found to import”错误的处理

    用Eclipse导入Java项目时,经常会出现“No projects are found to import”错误(尤其是导入网上下载的项目时),这是因为文件夹里面没有.project和.class ...

  9. 面试问题整理笔记系列 一 Java线程类

    1.sleep()和wait()区别 sleep() 方法:线程主动放弃CPU,使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态.典型地,sleep() ...

  10. 框架SpringMVC笔记系列 二 传值

    主题:SpringMVC(第一节中再回顾复习一次) 学习资料参考网址: 1.http://www.icoolxue.com 2.http://haohaoxuexi.iteye.com/blog/13 ...