1、Swift入门学习笔记(第一版),对Swift的基础知识点进行梳理总结。知识点一直在变,只是作为参考,以苹果官方文档为准~
2、在学习完基本的知识点以后会结合官方文档及相关资料,在此版本的基础上进行添加更改。
十五、构造过程(2)及析构过程
一、构造过程(2)
前一篇文章讲了构造过程的前一部分,链接如下
构造过程(1)部分
6、可失败构造器
“失败”是指:给构造器传入无效的参数值或缺少某种所需的外部资源,又或不满足某种必要条件等,在构造自身的过程中有可能失败
语法:init
后面加?
,同时通过return nil
表失败情况
注意:严格来说构造器不支持返回值,只有在失败是用return nil
。其他情况下禁用。
struct Milk {
let securityMonth:Int
init?(securityMonth:Int) {
if securityMonth <= 0 {
return nil
}
self.securityMonth = securityMonth
}
}
let milk1 = Milk(securityMonth:12)
if milk1 != nil {
print("Success")
}
let milk2 = Milk(securityMonth: -1)
if milk2 == nil {
print("Fail")
}
Output:
Success
Fail
7、枚举类型的可失败构造器
7.1、常规枚举
enum TheseThree { //傲娇的取名三人行吧~哈哈
case Zhu,Shui,Hu
init?(symbol:Character) {
switch symbol {
case "Z":self = .Zhu
case "S":self = .Shui
case "H":self = .Hu
default:return nil
}
}
}
let onePerson = TheseThree(symbol: "Z")
print(onePerson)
let anotherPerson = TheseThree(symbol: "A") //不符合情况的symbol传入
print(anotherPerson)
Output:
Optional(构造过程.TheseThree.Zhu)
nil
7.2、带原始值的枚举类型
带原始值的枚举类型,会自带一个可失败构造器init?(rawValue:)
enum PetAnimal:Character { //傲娇的取名三人行吧~哈哈
case Dog = "D",Cat = "C",Pig = "p"
}
let pet1 = PetAnimal(rawValue: "D")
print(pet1)
let pet2 = PetAnimal(rawValue: "A")
print(pet2)
Output:
Optional(构造过程.PetAnimal.Dog)
nil
8、类的可失败构造器
只有在所有的类属性初始化后和所有类之间的构造器之间的代理调用玩才能return nil
错误示范:
正确示范:
//所有类属性初始化后
class Person {
let name:String!
init?(name:String) {
self.name = name
if name.isEmpty {return nil}
}
}
9、构造失败的传递
可失败构造器可代理其他构造器,无所谓失败或不可失败
但是无论向上代理or横向代理,若代理的是可失败,触发构造失败行为,整个构造过程会立即终止,接下来任何的构造代码都将不会被执行
class Children:Person {
let age:Int!
init?(name:String,age:Int) {
self.age = age
super.init(name: name) //name构造失败整个失败
if age < 0 {return nil}
}
}
let child1 = Children(name: "",age: 10) //->在super那一步失败,所以代理失败,整个构造终止,可以通过断点调试查看
print(child1)
Output:
nil
但是一个不可失败的构造器不能去调用一个可失败的构造器。如果去调用父类的可失败构造器,虽然用解包可以解决,但是一旦父类的可失败构造器返回了nil,那么程序直接崩溃。
10、重写一个可失败构造器
子类的可失败构造器可重写基类的可失败构造器
子类的非可失败构造器可重写可失败构造器
换言之:
可失败可以重写,且可重写为非可失败
非可失败也可以重写,但是不能重写为可失败
常常用init?
来定义可失败构造器,但也可通过init!
来定义,自动解包,但要处理是否触发失败
11、必要构造器
required
修饰所有该类的子类都必须实现该构造器
class SomeClass {
required init() {
//必要构造器实现代码
}
}
//子类重写父类必要构造器时,只需required修饰符保证子类也是必要构造器,不需要override修饰符
class SomeSubclass:SomeClass {
required init() {
//必要构造器实现代码
//如果继承的构造器能满足必要构造器的需求,则无需在子类中提供必要构造器的实现
}
}
12、通过闭包和函数来设置属性的默认值
func getAge@H_742_301@()->Int {
return 21
}
class Man {
var age: Int = getAge()
var name = {
return "Zhu"
}() //空的小括号,告诉编译器立刻执行此闭包。忽略,则将闭包赋值给了属性,而不是返回值赋给了属性
}
var a = Man()
print(a.age,a.name)
Output:
21 Zhu
注意:闭包初始化属性值时,不能在闭包里访问其他的属性,即使有默认值。以及不能使用self属性及调用方法
二、析构过程
除了使用自己的资源(文件等),其他的Swift会通过ARC处理实例的内存管理
deinit {
//执行析构过程
}
子类继承父类析构器,在子类析构实现最后,父类析构自动调用。子类未提供,父类析构器也会被调用
具体实现设计内存管理,后文会讲