Swift的 convenience && designated init

http://www.th7.cn/Program/IOS/201603/789227.shtml

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

class ClassA {
    let numA: Int
    // 不加修饰的 init 方法都需要在方法中保证所有非 Optional 得实例变量被赋值初始化
    init(num: Int) {
        numA = num
    }
}

class ClassB: ClassA {
    let numB: Int
    override init(num: Int) {
        numB = num + 1  // 在 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 ? 10000 : 1) // 所有的 convenience 初始化方法都必须调用同一个类中的 designated 初始化完成设置
    }
}

class ClassBB: ClassAA {
    let numB: Int
    override init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}

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

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

输出:10000和10001

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

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 ? 10000 : 1)
    }
}

class ClassBBB: ClassAAA {
    let numB: Int
    required init(num: Int) {
        numB = num + 1
        super.init(num: num)
    }
}

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

输出:10000和10001

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

时间: 2024-10-23 03:32:02

Swift的 convenience && designated init的相关文章

一步一步教你用Swift开发俄罗斯方块:No.6 变形记

The object of art is to give life shape - William Shakespeare 上一章节我们介绍了这个游戏最基本的组成元素,block,那么接下来我们就开始更为清晰和形象地了解如果做出来俄罗斯方块的shape吧.是的,就是这样的形状: 首先我们来新建一个类,名字叫做Shape:到这里新建一个类的步骤应该很熟练了吧. 我们来修改下面的代码 在代码的第一部分,我们先建立了一个枚举类型,这个enumeration用来辅助我们定义我们的shape的4个方向,无

Swift中的init方法

摘要:Swift有着超级严格的初始化方法,不仅强化了designated初始化方法的地位,所有不加修饰的init方法都需要在方法中确保非Optional的实例变量被赋值初始化,而在子类中,也强制调用super版本的designated初始化. 我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的. 其实就是安全.在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如

Swift的初始化方法

我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的. 其实就是安全.在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题.虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误. 所 以Swift有了超级严格的初始化方法.一方面,Swift强化了

从0开始学Swift笔记整理(三)

这是跟在上一篇博文后续内容: --Swift中相关的属性 存储属性 Swift中的属性分为存储属性和计算属性,存储属性就是Objective-C中的数据成员,计算属性不存储数据,但可以通过计算其他属性返回数据.存储属性可以存储数据,分为常量属性(用关键字let定义)和变量属性(用关键var定义). 存储属性概念: 我们在前面曾用到过属性,Employee类和Department结构体.它们的类图如下,Employee 的部门属性dept与Department之间进行了关联. 我们可以在定义存储属

iOS开发——swift篇&经典语法(八)初始化

初始化 初始化是类,结构体和枚举类型实例化的准备阶段.这个阶段设置这个实例存储的属性的初始化数值和做一些使用实例之前的准备以及必须要做的其他一些设置工作. 通过定义构造器(initializers)实现这个实例化过程,也就是创建一个新的具体实例的特殊方法.和Objective-C不一样的是,Swift的构造器没有返回值.它们主要充当的角色是确保这个实例在使用之前能正确的初始化. 类实例也能实现一个析构器(deinitializer),在类实例销毁之前做一些清理工作.更多的关于析构器(deinit

[IOS]swift自定义uicollectionviewcell

刚刚接触swift以及ios,不是很理解有的逻辑,导致某些问题.这里分享一下swift自定义uicollectionviewcell 首先我的viewcontroller不是直接继承uicollectionviewcontroller,而是添加的uicollectionview到我的storyboard, 然后再新建一个swift的文件,让这个swift继承uicollectionviewcell import Foundation class SVGCell :UICollectionView

Swift学习(3面向对象)

swift面向对象 1. 在swift中,默认在同一个项目中(同一个命名空间下),所有的类都是共享的,不需要import 所有的属性 var 也可以直接访问到 2.在swift中,所有的类都默认有一个命名空间,就是项目名称 3. ()  -> alloc  init.  swift中对应一个init()构造函数,作用是给成员变量分配内存空间并初始化 4.构造函数的写法: 一:必选属性的构造方法 1.给自己的属性分配内存空间并设置初始值 2.调用父类的构造函数,给父类的属性分配雷村空间设置初始值

Swift 2.0学习笔记(Day 42)——构造函数调用规则

原创文章,欢迎转载.转载请注明:关东升的博客 在构造函数中可以使用构造函数代理帮助完成部分构造工作.类构造函数代理分为横向代理和向上代理,横向代理只能在发生在同一类内部,这种构造函数称为便利构造函数.向上代理发生在继承的情况下,在子类构造过程中,要先调用父类构造函数初始化父类的存储属性,这种构造函数称为指定构造函数. 构造函数调用规则 Person和Student类示例: class Person { var name: String var age: Int func description(

Swift 2.0学习笔记(Day43)——构造函数继承

原创文章,欢迎转载.转载请注明:关东升的博客 Swift中的子类构造函数的来源有两种:自己编写和从父类继承.并不是父类的所有的构造函数都能继承下来,能够从父类继承下来的构造函数是有条件的,如下所示. l 条件1:如果子类没有定义任何指定构造函数,它将自动继承所有父类的指定构造函数. l 条件2:如果子类提供了所有父类指定构造函数的实现,无论是通过条件1继承过来的,还是通过自己编写实现的,它都将自动继承所有父类的便利构造函数. 下面看示例代码: class Person { var name: S