美文网首页
Swift5.1学习随笔之初始化器

Swift5.1学习随笔之初始化器

作者: SAW_ | 来源:发表于2020-04-28 11:42 被阅读0次

初始化器

  • 类、结构体、枚举都可以定义初始化器(init
  • 类有2种初始化器:指定初始化器、便捷初始化器

指定初始化器

init(parameters) {
    statements
}

便捷初始化器,添加关键字convenience

convenience init(parameters) {
    statements
}

1、每个类至少有一个指定初始化器,指定初始化器是类的主要初始化器

不指定初始化器,编译器自动生成init() {}初始化器

class Size {
    var width: Int = 0
    var height: Int = 0
    init() {} // 编译器自动生成,可以不写
}
var s = Size() 

自定义了初始化器,系统就不会生成默认的init() {}初始化器

class Size {
    var width: Int = 0
    var height: Int = 0
    init(width: Int, height: Int) {
        self.width = width
        self.height = height
    }
}
var s = Size() // 报错:Missing arguments for parameters 'width', 'height' in call
var s = Size(width: 10, height: 10) // 正确调用

2、默认初始化器总是类的指定初始化器
3、类偏向于少量指定初始化器,一个类通常只有一个指定初始化器
4、初始化器的相互调用规则

  • 指定初始化器必须从它的直系父类调用指定初始化器
  • 便捷初始化器必须从相同的类里调用另一个初始化器
  • 便捷初始化器必须调用一个指定初始化器

便捷初始化器必须调用一个指定初始化器
以下代码调用OK

class Size {
    var width: Int = 0
    var height: Int = 0
    init() {
        
    }
    init(width: Int, height: Int) {
        self.width = width
        self.height = height
    }
    init(width: Int) {
        self.width = width
    }
    init(height: Int) {
        self.height = height
    }
}
var s1 = Size()
var s2 = Size(width: 10, height: 10)
var s3 = Size(width: 10)
var s4 = Size(height: 10)

init(width: Int, height: Int)加上convenience关键词,变成便捷初始化器,编译器报错,提示内部必须调用一个指定初始化器

convenience init(width: Int, height: Int) {
    self.width = width
    self.height = height
} // 报错:'self.init' isn't called on all paths before returning from initializer

修改之后,内部可以调用init()init(width: Int)init(height: Int)任何一个

convenience init(width: Int, height: Int) {
    self.init() 
    self.width = width
    self.height = height
}
convenience init(width: Int, height: Int) {
    self.init(width: width)
    self.height = height
}
convenience init(width: Int, height: Int) {
    self.init(height: height)
    self.width = width
}

Swift设计的时候出于安全考虑,必须满足任何一个初始化器调用的时候,保证所有属性都是有值。

指定初始化器必须从它的直系父类调用指定初始化器

class Person {
    var age: Int
    init(age: Int) {
        self.age = age
    }
    convenience init() {
        self.init(age: 0)
    }
}
class Student: Person {
    var score: Int
    init(age: Int, score: Int) {
        self.age = age // 报错:'self' used in property access 'age' before 'super.init' call
        self.score = score
    } //报错:'super.init' isn't called on all paths before returning from initializer
}

修改:必须调用父类指定初始化器,必须放置后面实现

class Student: Person {
    var score: Int
    init(age: Int, score: Int) {
        self.score = score
        super.init(age: age) //必须调用父类指定初始化器,必须放置后面实现
    }
}
两段式初始化

Swift在编码安全方面做了很多,为了保证初始化过程的安全,设置了两段式初始化、安全检查

第1阶段:初始化所有存储属性

  • 外层调用指定\便捷初始化器
  • 分配内存给实例、但未初始化
  • 指定初始化器确保当前类定义的存储属性都初始化
  • 指定初始化器调用父类的初始化器,不断向上调用,形成初始化器链

第2阶段:设置新的存储属性值

  • 从顶部初始化器往下,链中的每一个指定初始化器都有机会进一步定制实例
  • 初始化器现在能够使用self(访问、修改它的属性,调用它的实例方法等等)
  • 最终,链中任何便捷初始化器都有机会定制实例以及使用self
自动继承
  1. 如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器
class Person {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    init(age: Int) {
        self.age = age
        self.name = ""
    }
}

class Student: Person {
    
}

var s1 = Student() //报错:Missing argument for parameter 'age' in call
var s2 = Student(age: 10) //继承父类的初始化器
var s3 = Student(age: 10, name: "jack") //继承父类的初始化器
  1. 如果子类提供了父类所有指定初始化器的实现(要么通过1继承,要么重写)
    • 子类自动继承所有的父类便捷初始化器
class Person {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    init() {
        self.age = 0
        self.name = ""
    }
    convenience init(age: Int) {
        self.init(age: age, name: "")
    }
    convenience init(name: String) {
        self.init(age: 0, name: name)
    }
}

class Student: Person {
    //子类没有实现任何初始化器
}

从下面截图中可以看出,子类Student拥有了父类Person定义的所有初始化器

  1. 就算子类添加了更多的便捷初始化器,这些规则依然适用
  2. 子类以便捷初始化器的形式重写父类的指定初始化器,也可以作为满足规则2的一部分
可失败初始化器

1.类、结构体、枚举都可以用init?定义可失败初始化器

class Person {
    var name: String
    init?(name: String) {
        if name.isEmpty { 失败
            return nil //如果传入的字符串为空,就返回nil,初始化
        }
        self.name = name
    }
}
var p1 = Person(name: "")
var p2 = Person(name: "jack")
print(p1) // nil
print(p2) // Optional(SwiftDDDDD.Person)
  1. 不允许同时定义参数标签、参数个数、参数类型相同的可失败初始化器和非可失败初始化器
class Person {
    var name: String
    init?(name: String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
    init(name: String) { //报错:Invalid redeclaration of 'init(name:)'
        self.name = name
    }
}
  1. 可以使用init!定义隐式解包的可失败初始化器
  2. 可失败初始化器可以调用非可失败初始化器,非可失败初始化器调用可失败初始化器需要进行解包
class Person {
    var name: String
    convenience init?(name: String) {
        self.init()
        if name.isEmpty {
            return nil
        }
    }
    init() {
        self.name = ""
    }
}
class Person {
    var name: String
    init?(name: String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
    convenience init() {
        self.init(name: "")!
    }
}
class Person {
    var name: String
    init!(name: String) {
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
    convenience init() {
        self.init(name: "")
    }
}

相关文章

  • Swift5.1学习随笔之初始化器

    初始化器 类、结构体、枚举都可以定义初始化器(init) 类有2种初始化器:指定初始化器、便捷初始化器 指定初始化...

  • Swift5.1学习随笔之指针

    Swift中也有专门的指针类型,这些都被定义为Unsafe(不安全的),常见的有以下4种类型 UnsafePoin...

  • Swift5.1学习随笔之fatalError

    如果遇到严重问题,希望结束程序运行,可以直接使用fatalError函数抛出错误(这是无法通过do-catch捕捉...

  • Swift5.1学习随笔之mutating

    结构体和枚举是值类型,默认情况下,值类型的属性不能被自身的实例方法修改在func关键字前面加mutating可以允...

  • Swift5.1学习随笔之常量

    Swift中的常量用let修饰 1、只能赋值一次 2、它的值不要求在编译时期确定,但是使用之前必须赋值一次 3、常...

  • Swift5.1学习随笔之@discardableResult

    在func前面加@discardableResult,可以消除:函数调用后返回值未被使用的警告⚠️ 或者可以用下划...

  • Swift5.1学习随笔之属性

    swift中跟实例相关的属性可以分为2大类 1、存储属性(Stored Property)2、计算属性(Compu...

  • Swift5.1学习随笔之协议Protocol

    协议Protocol 协议可以用来定义方法、属性、下标声明,协议可以被枚举、结构体、类遵守(多个协议用逗号隔开) ...

  • Swift5.1学习随笔之扩展(Extension)

    Swift中的扩展,类似于OC中的分类Category 扩展可以为枚举、类、结构体、协议添加新功能可以添加方法、计...

  • Swift5.1学习随笔之函数func

    Swift中的函数用func关键字定义 举个? 无返回值的函数 有3中表达写法 隐式返回 如果整个函数体是一个单一...

网友评论

      本文标题:Swift5.1学习随笔之初始化器

      本文链接:https://www.haomeiwen.com/subject/dixvwhtx.html