美文网首页
Swift中的构造方法

Swift中的构造方法

作者: 落叶刺客 | 来源:发表于2017-05-24 20:08 被阅读113次

结构体和类在创建实例的过程中需要进行一些初始化的工作,这个过程被称之为构造过程。同样,这些实例在使用完成之后需要做一些清除工作,这个过程被称之为析构过程。下面,我们来学习一下Swift中的构造和析构。

1、构造函数

结构体和类在实例化的过程中会调用init()方法,而这个方法被称之为构造函数。与Objective-C中的构造函数不同,Swift中构造函数没有返回值,可以重载。通常情况下,在定义一个类或者结构体时,不需要我们编写构造函数,系统会提供一个默认的构造函数:

class Person {
    var age: Int = 0
    var name: String?
    
    lazy var stu: Student = Student()
}

struct Student {
    var no: Int = 0
    var sex: String?
}

// 实例化一个Person对象
let p = Person()
p.age = 20
p.name = "Lilei"
p.stu.no = 1701
p.stu.sex = "Male"

以前在Objective-C中,我们实例化一个类时,一般会明确调用alloc和init方法。比如说,创建一个UIView对象:

UIView *view = [[UIView alloc] init];

但是,在Swift中,如果要创建一个UIView对象,好像不用调用任何方法,直接使用类型加小括号就可以了:

let view = UIView()

实际上,在Swift中创建一个对象,仍然需要调用方法,而小括号就代表着方法的调用。在上面的代码中,我们实际上调用了系统默认的init()方法。以上面的Person类为例,它实际上应该是类似于下面这样的:

class Person {
    var age: Int = 0
    var name: String?
    
    lazy var stu: Student = Student()
    
    init() {
        
    }
}

struct Student {
    var no: Int = 0
    var sex: String?
    
    init() {
        
    }
}

2、构造函数与存储属性的初始化

我们都知道,存储属性在定义的时候需要初始化,否则编译器会报错。但是实际上,除了可以在定义的时候初始化之外,还可以在构造函数中对其进行初始化:

class Person {
    var age: Int
    var name: String
    
    lazy var stu: Student = Student(no: 0, sex: "Male")
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}

struct Student {
    var no: Int
    var sex: String
    
    init(no: Int, sex: String) {
        self.no = no
        self.sex = sex
    }
}

// 在实例化的过程中,通过构造函数对它的属性进行初始化
let p = Person(age: 20, name: "LeBron")
p.stu.no = 1701
p.stu.sex = "Femal"

以上面的Person类为例,其属性age和name在定义的时候没有被初始化,但是在实例化的时候,我们通过构造函数分别给它们初始化为20和LeBron。构造函数只能初始化存储属性(不管常量还是变量都可以),不能初始化计算属性(因为计算属性不需要存储数据)和静态属性(因为静态属性跟具体的实例无关)。

3、构造函数重载

在了解什么是构造函数重载之前,我们先来了解一下什么叫做函数重载。函数重载就是指函数名(或者沿袭Objective-C中叫方法也行)相同,但是参数不同。参数不同又包括参数标签不同、参数个数不同和参数类型不同。Objective-C中没有方法重载的概念,因为在Objective-C中调用方法的本质是发送消息,如果方法名相同,系统在发送消息时,就不知道该把消息发送给谁。构造函数重载,就是指同一个类或者结构体中可以有多个init()函数,但是它们的参数不同。比如说:

// 类的构造函数
class Person {
    var age: Int
    var name: String
    
    // 构造函数1
    init() {
        self.age = 0
        self.name = ""
    }
    
    // 构造函数2
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    // 构造函数3
    init(A age: Int, N name: String) {
        self.age = age
        self.name = name
    }
}

// 调用构造函数1
let p1 = Person()
p1.age = 33
p1.name = "James"
print("age = \(p1.age), name = \(p1.name)")  // age = 33, name = James

// 调用构造函数2
let p2 = Person(age: 33, name: "Anthony")
print("age = \(p2.age), name = \(p2.name)")  // age = 33, name = Anthony

// 调用构造函数3
let p3 = Person(A: 35, N: "Wade")
print("age = \(p3.age), name = \(p3.name)")  // age = 35, name = Wade

上面的Person类中定义了3个构造函数,它们之间是重载的关系,在实例化的过程中,通过调用不同的构造函数来创建对象。

4、构造函数代理

有时候为了减少代码重复,在定义构造函数时,可以在一个构造函数中调用另外一个构造函数,这种情况被称之为构造函数代理。比如说:

class Person {
    var age: Int
    var name: String
    
    // 构造函数1
    convenience init() {
        // 调用了构造函数2
        self.init(age: 0, name: "")
    }
    
    // 构造函数2
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    // 构造函数3
    init(A age: Int, N name: String) {
        self.age = age
        self.name = name
    }
}

在上面的代码中,我们在构造函数1中调用了构造函数2,这种情况就是构造函数代理。在结构体中,构造函数调用其它构造函数时,可以直接调用,前面不用加关键字convenience。但是,由于类具有继承关系,类里面的构造函数代理又相对复杂一点。

如果构造函数代理是发生在同一个类的内部,那么这种构造函数便称之为便利构造函数,比如说像上面那种情况就是便利构造函数;如果构造函数代理是发生在子类中,那么子类在构造过程中需要调用父类的构造函数,初始化父类的存储属性,这种构造函数称之为指定构造函数。比如说:

class Person {
    var age: Int
    var name: String
    
    init() {
        self.age = 0
        self.name = ""
    }
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}

class Student: Person {
    
    var no: Int
    var height: Double
    
    // 构造函数
    init(age: Int, name: String, no: Int, height: Double) {
        
        self.no = no
        self.height = height
        
        // 调用父类的构造函数,对父类中的属性进行初始化
        super.init(age: age, name: name)
    }
    
    // 便利构造函数
    convenience override init(age: Int, name: String) {
        
        // 初始化no和height
        self.init(age: age, name: name, no: 0, height: 0.0)
    }
}

// 实例化Student
let stu = Student(age: 20, name: "Anthony", no: 1701, height: 1.72)

子类中构造函数的代理涉及到了继承,所以相关代码的解释我准备放在继承中进行。

5、析构函数

析构过程与构造过程相反,析构在实例释放的时候需要清除一些资源。析构过程会调用deinit函数。deinit函数又被称为析构函数,它没有返回值,没有参数,也不需要小括号。析构函数不能重载。析构函数的具体实例如下:

// 类的构造函数
class Person {
    var age: Int
    var name: String
    
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
    
    convenience init(A age: Int, N name: String) {
        self.init(age: age, name: name)
    }
    
    deinit {
        self.age = 0
        self.name = ""
    }
}

var p: Person? = Person(age: 20, name: "James")
print("age = \(p!.age), name = \(p!.name)")

// 调用析构函数,释放资源
p = nil

析构函数的调用使得实例被赋值为nil,表示实例需要释放资源。p = nil是触发析构函数调用的条件。

相关文章

  • Swift 引发的一场知识暴动

    一、构造方法 在Swift中,主要有三种构造方法:系统构造方法、普通构造方法与便利构造方法。构造方法一般都是以 i...

  • Swift学习:构造器(中)

    Swift之构造器(上)Swift之构造器(中)Swift之构造器(下) 本篇继续对Swift中的构造器进行介绍,...

  • Swift学习:构造器(下)

    Swift之构造器(上)Swift之构造器(中)Swift之构造器(下) 本篇主要介绍Swift中构造器的一些特殊...

  • Swift中的构造方法

    结构体和类在创建实例的过程中需要进行一些初始化的工作,这个过程被称之为构造过程。同样,这些实例在使用完成之后需要做...

  • Swift 的构造器(一)

    前言 本文主要是Swift的构造器相关知识,另加少部分的OC中的init方法(还有少许Java相关的构造方法...

  • Swift学习:构造器(上)

    Swift之构造器(上)Swift之构造器(中)Swift之构造器(下)Swift赋予自定义类型更加丰富的功能,一...

  • Swift子类重写父类构造函数

    swift中子类重写父类构造方法: 如果父类没有指定构造方法(带参数的构造方法), 子类重写父类构造方法就不需要调...

  • Swift中构造方法的解析

    一、引言 二、构造方法的复写与重载 创建一个继承于NSObject的类,复写构造方法,代码示例如下: class ...

  • Swift之init构造方法

    构造方法是一个类创建对象最先也是必须调用的方法,在Swift语言体系中,构造方法与普通的方法分界十分严格,从格式写...

  • Swift面向对象

    创建一个类 类的四种属性 类的构造 swift类构造过程 指定构造器 便利构造器 KVC构造器 实例方法和类方法 ...

网友评论

      本文标题:Swift中的构造方法

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