构成过程
;相反这些实例最后被释放的时候需要进行一些清楚资源的工作,这个过程称为析构过程
.init
方法,称为构造函数
;在析构过程中会调用deinit
方法,称为析构函数
。(结构体或者类创建实例直接结构体名或类名后面加个小括号,其实就是调用了默认的构造方法init()
)。初始化存储属性
和其他初始化。如果在构造函数时初始化了这些存储属性,那么在定义这些属性时就不用初始化了。计算属性不保存数据,所以不需要初始化,构造函数也不能初始化静态属性,因为他们与具体实例个体无关。枚举没有存储属性,所以也没有init的构造函数。init() {
}
示例:
class Employee{
let no: Int
var name: String
init() {
no = 0
name = ""
}
}
struct Rectangle{
var width:Double = 0.0
var height = 0.0
}
Rectangle(width: 10.0, height: 10.0)
上面结构体重使用了默认构造函数,结构体中按照从上到下的顺序吧属性名作为参数标签,依次提供参数,不用声明构造函数,直接可以按照属性参数标签赋值初始化实例。注意这种默认构造函数,值使用于结构体,在类中不能使用。
与oc不同的是Swift的构造函数没有返回值。
class Rectangle {
var width: Double
var height: Double
init() {
width = 0.0
height = 0.0
}
init(W witdh:Double, H height: Double) {
self.width = witdh
self.height = height
}
init(length: Double) {
self.width = length
self.height = length
}
}
let r1 = Rectangle()
let r2 = Rectangle(W: 100, H: 100)
let r3 = Rectangle(length: 100)
当属性名称和构造函数参数名相同时,添加self.
来区分是属性函数参数。
构造函数代理
。但是结构体和类构造函数代理是有所不同的。struct Rectangle {
var width: Double
var height: Double
init() {
self .init(W: 100, H: 100)
}
init(W witdh:Double, H height: Double) {
self.width = witdh
self.height = height
}
init(length: Double) {
self.init(W: length, H: length)
}
}
let r1 = Rectangle()
let r2 = Rectangle(W: 100, H: 100)
let r3 = Rectangle(length: 100)
结构体因为不存在继承,所以构造函数代理很简单,就是在同一类型中通过self.init(...)
语句来调用其他构造函数,self.init
构造函数就称为构造函数代理
。
横向代理
和向上代理
。横向代理
类似于结构体的构造函数代理,发生在同一类内部,这种构造函数称为便利构造函数
(convenience initializer)class Rectangle {
var width: Double
var height: Double
convenience init() {
self .init(W: 100, H: 100)
}
init(W witdh:Double, H height: Double) {
self.width = witdh
self.height = height
}
convenience init(length: Double) {
self.init(W: length, H: length)
}
}
let r1 = Rectangle()
let r2 = Rectangle(W: 100, H: 100)
let r3 = Rectangle(length: 100)
类中构造函数横向代理必须前面加上convenience
关键字
向上代理
发生在继承情况下,在子类构造过程中要先调父类构造函数,初始化父类的存储属性,这种构造函数称为指定构造函数
(designated initializer)class Person{
var name: String
var age: Int
func description() -> String {
return "\(name)的年龄是\(age)"
}
init(name:String, age:Int) { //指定构造函数,没调用self.init
self.name = name
self.age = age
}
convenience init(name:String) { //便利构造函数,调用了self.init
self.init(name: name, age: 18)
}
convenience init(){ //便利构造函数,调用了self.init
self.init(name: "Jack MA")
self.age = 19 //未初始化的属性要放在self.init之后,放在前面会编译报错
}
}
class Student: Person {
var school: String
init(name: String, age: Int,school:String) {//指定构造函数,虽然调用了super.init,但没调用self.init
self.school = school //因为没调self.init所以可以school赋值,默认会在构造过程中初始化,如果放在super.init后面初始化就会报错
// self.test() //编译报错
super.init(name: name, age: age)
// super.init(name: "马云")
self.name = ""
self.age = 18//age是属性父类的属性,所以要在super.init赋值才有意义,同样放在前面会编译报错
self.test()
}
override convenience init(name: String, age: Int) { //虽然是重写父类的构造函数,但是还是调用了self.init,所以还是便利构造函数
self.init(name: name, age: age, school: "杭州师范大学")
self.school = "清华大学" //放在self.init之前会报错,因为只有在调用了指定构造函数后才会为存储属性分配内存和初始化
self.name = ""
}
func test() {
print("这是一个实例方法")
}
}
指定构造函数必须调用其直接父类的指定构造函数。
(也就是说如果一个类有父类,那么他的指定构造函数必须调用父类的指定构造函数,调用父类的便利构造函数或者不调用super.init编译都会报错。)便利构造函数必须调用同一类中定义的其他构造函数。
便利构造函数必须最终以调用一个指定构造函数结束。
(也就是说一个类中如果有便利构造函数的话,最少有一个调用了该类的指定构造函数)所有指定构造函数
。(也就是说如果父类有多个指定构造函数,子类的指定构造函数只调用了一个父类的指定构造函数super.init或者没有重写父类所有的指定构造函数,那么子类不能继承父类的构造函数,包括自定构造函数和便利构造函数,初始化时只能用自己的构造函数)deinit
,没有返回值也没有参数,也不需要参数的小括号,所以不能重载。class Rectangle {
var width: Double
var height: Double
convenience init() {
self .init(W: 100, H: 100)
}
init(W witdh:Double, H height: Double) {
self.width = witdh
self.height = height
}
convenience init(length: Double) {
self.init(W: length, H: length)
}
deinit {
print("调用析构函数,正在释放实例对象!!!")
width = 0.0
height = 0.0
}
}
print("初始化")
var r : Rectangle? = Rectangle(length: 100)
print("将要设置为nil")
r = nil
print("释放")
析构函数只适用于类,不适用于枚举和结构体
。Swift中内存管理采用自动引用计数(ARC),不需要析构函数释放不需要的实例内存资源,但还是有一些清除工作要在这里完成,如关闭文件,移除通知监听者等。