Des*_*ume 122 initialization swift
由于Swift支持方法和初始化程序重载,因此您可以将多个init并排放在一起,并使用您认为方便的方法:
class Person {
var name:String
init(name: String) {
self.name = name
}
init() {
self.name = "John"
}
}
Run Code Online (Sandbox Code Playgroud)
那么convenience关键字为什么会存在呢?是什么让以下更好?
class Person {
var name:String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "John")
}
}
Run Code Online (Sandbox Code Playgroud)
nhg*_*rif 221
现有的答案只讲述了一半的convenience故事.故事的另一半,即现有答案所涵盖的一半,回答了Desmond在评论中发布的问题:
为什么Swift会强迫我把它放在
convenience我的初始化器前面,因为我需要self.init从它调用?`
我在这个答案中略微触及它,其中我详细介绍了 Swift的几个初始化规则,但主要关注的是这个required词.但是,这个答案仍在解决与这个问题和这个答案相关的问题.我们必须了解Swift初始化器继承的工作原理.
由于Swift不允许未初始化的变量,因此无法保证从您继承的类继承所有(或任何)初始值设定项.如果我们将任何未初始化的实例变量子类化并添加到子类中,我们就会停止继承初始化器.在我们添加自己的初始化器之前,编译器会对我们大喊大叫.
为了清楚起见,未初始化的实例变量是任何未赋予默认值的实例变量(请记住,选项和隐式解包的选项会自动采用默认值nil).
所以在这种情况下:
class Foo {
var a: Int
}
Run Code Online (Sandbox Code Playgroud)
a是一个未初始化的实例变量.除非我们给出a默认值,否则不会编译:
class Foo {
var a: Int = 0
}
Run Code Online (Sandbox Code Playgroud)
或者a在初始化方法中初始化:
class Foo {
var a: Int
init(a: Int) {
self.a = a
}
}
Run Code Online (Sandbox Code Playgroud)
现在,让我们看看如果我们进行子类化会发生什么Foo,是吗?
class Bar: Foo {
var b: Int
init(a: Int, b: Int) {
self.b = b
super.init(a: a)
}
}
Run Code Online (Sandbox Code Playgroud)
对?我们添加了一个变量,我们添加了一个初始化器来设置一个值,b以便它编译.根据你来自哪种语言,你可能会期望它Bar继承了Foo初始化器,init(a: Int).但事实并非如此.怎么可能呢?怎样Foo的init(a: Int)知道如何分配一个值b变量Bar添加?它没有.因此,我们无法Bar使用无法初始化所有值的初始化程序初始化实例.
这与这有什么关系convenience?
那么,让我们看一下初始化器继承的规则:
规则1
如果您的子类没有定义任何指定的初始值设定项,它会自动继承其所有超类指定的初始值设定项.
规则2
如果您的子类提供了所有超类指定初始化程序的实现 - 通过按照规则1继承它们,或者通过提供自定义实现作为其定义的一部分 - 那么它会自动继承所有超类便捷初始化程序.
注意规则2,它提到了便利初始化器.
所以convenience关键字的作用是向我们指示哪些初始值设定项可以由添加没有默认值的实例变量的子类继承.
我们来看这个示例Base类:
class Base {
let a: Int
let b: Int
init(a: Int, b: Int) {
self.a = a
self.b = b
}
convenience init() {
self.init(a: 0, b: 0)
}
convenience init(a: Int) {
self.init(a: a, b: 0)
}
convenience init(b: Int) {
self.init(a: 0, b: b)
}
}
Run Code Online (Sandbox Code Playgroud)
注意我们convenience这里有三个初始化器.这意味着我们有三个可以继承的初始化器.我们有一个指定的初始化程序(指定的初始化程序只是任何不是便利初始化程序的初始化程序).
我们可以用四种不同的方式实例化基类的实例:
所以,让我们创建一个子类.
class NonInheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
}
Run Code Online (Sandbox Code Playgroud)
我们继承自己Base.我们添加了自己的实例变量,但我们没有给它一个默认值,所以我们必须添加自己的初始化器.我们添加了一个,init(a: Int, b: Int, c: Int)但它与Base类的指定初始化程序的签名不匹配:init(a: Int, b: Int).这意味着,我们不会继承任何初始化器Base:
那么,如果我们继承了会发生什么Base,但是我们继续实施了一个与指定的初始化器相匹配的初始化器Base?
class Inheritor: Base {
let c: Int
init(a: Int, b: Int, c: Int) {
self.c = c
super.init(a: a, b: b)
}
convenience override init(a: Int, b: Int) {
self.init(a: a, b: b, c: 0)
}
}
Run Code Online (Sandbox Code Playgroud)
现在,除了我们直接在这个类中实现的两个初始化器之外,因为我们实现了初始化器匹配Base类的指定初始化器,所以我们继承了所有Base类的convenience初始化器:
具有匹配签名的初始化程序被标记为的事实在convenience此处没有区别.它只意味着Inheritor只有一个指定的初始化程序.因此,如果我们继承Inheritor,我们只需要实现一个指定的初始化器,然后我们继承了Inheritor方便初始化器,这反过来意味着我们已经实现了所有Base的指定初始化器并且可以继承它的convenience初始化器.
主要是清晰度.从你的第二个例子,
init(name: String) {
self.name = name
}
Run Code Online (Sandbox Code Playgroud)
是必需的或指定的.它必须初始化所有常量和变量.便捷初始化程序是可选的,通常可用于简化初始化.例如,假设您的Person类具有可选的变量gender:
var gender: Gender?
Run Code Online (Sandbox Code Playgroud)
性别是一个枚举
enum Gender {
case Male, Female
}
Run Code Online (Sandbox Code Playgroud)
你可以有像这样的便利初始化器
convenience init(maleWithName: String) {
self.init(name: name)
gender = .Male
}
convenience init(femaleWithName: String) {
self.init(name: name)
gender = .Female
}
Run Code Online (Sandbox Code Playgroud)
便利初始化程序必须在其中调用指定或必需的初始化程序.如果您的类是子类,则必须super.init() 在其初始化内调用.
好吧,首先我想到的是它在类继承中用于代码组织和可读性.继续Person上课,想想这样的场景
class Person{
var name: String
init(name: String){
self.name = name
}
convenience init(){
self.init(name: "Unknown")
}
}
class Employee: Person{
var salary: Double
init(name:String, salary:Double){
self.salary = salary
super.init(name: name)
}
override convenience init(name: String) {
self.init(name:name, salary: 0)
}
}
let employee1 = Employee() // {{name "Unknown"} salary 0}
let john = Employee(name: "John") // {{name "John"} salary 0}
let jane = Employee(name: "Jane", salary: 700) // {{name "Jane"} salary 700}
Run Code Online (Sandbox Code Playgroud)
使用便利初始化程序,我能够创建一个Employee()没有值的对象,因此这个词convenience
| 归档时间: |
|
| 查看次数: |
22945 次 |
| 最近记录: |