前言
方法是与某些特定类型相关联的。
- 方法另一个说法也叫成员函数,英文单词为 method,而不是表示函数的单词 function。
- 方法中定义的是类的行为。
- 函数的性质对于方法同样适用。
枚举、结构体、类中都可以定义方法,方法分为实例方法和类方法两种。
1、实例方法
由实例对象调用的方法。
- 实例方法在类内部的定义和实现上看起来同函数没有区别。
- 实例方法可以直接访问类的属性,但是不能直接修改结构体和枚举中的属性。
在访问类的属性时,直接引用属性的名称即可,当然也可以加一个
self
前缀。class Student { func sayHello() { print("Hello") }}let newStudent = Student()newStudent.sayHello() // Hello
类型的每一个实例都有一个隐含属性叫做
self
,self
完全等同于该实例本身。- 可以在一个实例的实例方法中使用隐含的
self
属性来引用当前实例,从而获得对实例其他属性和方法的访问。 - 正由于是隐含的,这个
self
大部分情况下都可以省略,如果没有明确的写self
,则 Swift 会假定是指当前实例的属性和方法。 - 但是在类型中,存在同名局部变量的情况下,
self
就不能省略。 - 在闭包中使用当前实例的属性或者方法时,编译器会提示加上
self
(除非方法参数中的noescape
闭包)。
- 可以在一个实例的实例方法中使用隐含的
2、类型方法
类型方法不属于任何一个类对象,而是属于类本身。
- 类型方法可以通过类名直接调用。
- 类型方法不能调用类的变量属性,因为使用类型方法,并不需要初始化类,没有空间存储对象,因而也并没有空间来保存变量。
- 在类型方法的定义中不能使用
self
。 如果要定义一个类型方法,在结构体或者枚举中使用关键字
static
,在类中使用关键字class
。// 结构体中定义类型方法struct Example { static func sayHello() { print("Hello") }}Example.sayHello() // Hello
// 类中定义类型方法class Student { class func sayHello() { print("Hello") }}Student.sayHello() // Hello
3、初始化方法
类型的方法在创建对象之后,使用对象的属性之前,我们得做好相应的属性初始化,否则在没有初始化的前提下,就会报错。遇到这种情况时,一种解决方案是在定义变量时就做好初始化,另一种解决方案就是使用初始化方法。
- Swift 中的同普通方法不同,方法名是固定的
init
,没有返回值,方法名init
前面也不加func
关键字。 - 初始化方法可以接受参数,
init
初始化方法的参数,在创建对象时就可以传入。 初始化方法可以有多个,并且每一个在方法名上都一样,都是
init
,但是参数上要有所不同。class Rect { var width: Float var height: Float init() { width = 0.0 height = 0.0 } init(w: Float, h: Float) { width = w height = h }}let rect1 = Rect()print("\(rect1.width)", "\(rect1.height)") // 0.0 0.0let rect2 = Rect(w: 10, h: 20)print("\(rect2.width)", "\(rect2.height)") // 10.0 20.0
- Swift 中的同普通方法不同,方法名是固定的
3.1 默认初始化方法
Swift 语言将为类型中所有属性都已提供默认值的且自身没有定义任何构造器的类型提供一个默认的初始化方法。
- 对存储属性都初始化了之后,可以用默认初始化方法实例化对象。
- 对类存储属性设置为可选存储属性(
?
),可以用默认初始化方法实例化对象。 对类存储属性设置为隐式解包可选(
!
),可以使用默认初始化方法实例化对象。class Student { var name: String? var age: Int = 8}// 使用默认初始化方法初始化对象let newStudent = Student()
3.2 便利初始化方法
调用独立初始化方法的初始化方法,就叫便利初始化方法,正像它的名字,是为了便利我们调用而出现的。
- 在它的实现里面,必须调用一个其他的初始化方法。
便利初始化方法,在
init
前面加上convenience
关键字即可。class Rect { var width: Float var height: Float // 一般初始化方法 init(width: Float, height: Float) { self.width = width self.height = height } // 便利初始化方法 convenience init(w: Float, h: Float) { self.init(width: w, height: h) }}let rect = Rect(w: 10, h: 20)print("\(rect.width)", "\(rect.height)") // 10.0 20.0
4、反初始化方法
我们假设一个场景,我要建立一个数据库访问类,在初始化时打开链接,如果程序退出,连接不释放,资源就会浪费。
所以我们引入一种新的特殊方法,跟初始化方法相对,叫反初始化方法。
反初始化方法的方法名为
deinit
,在把对象设置为nil
时,系统会自动调用反初始化方法。deinit { self.conn.close() self.conn = nil}
5、变异方法
结构体和枚举是值类型的,一般情况下,值类型的属性不能在它的实例方法中被修改。
如果确实需要在某个具体的方法中修改结构或者枚举的属性,则在声明方法时,需要在方法定义前加上关键字
mutating
,此时这个方法就变成了一个 “变异方法”。struct Example { var str = "xiaoming" mutating func sayHello(name: String) { str = "Hello \(name)" }}let xiaoming = Example()xiaoming.sayHello(name: "Xiaoming")
6、重载
有相同名字不同参数的方法或函数的写法有一个专门的术语来描述,叫做 “重载”。
- 在别的语言中,重载的情况只出现在类定义里,但是在 Swift 语言中,类中的实例方法可以重载,而全局的函数也可以重载。
- Swift 语言中,只要参数名或者参数别名或者参数类型不同就可以实现重载。
- Swift 语言中,两个方法相同,尽管参数数据类型一样,但是参数名不同,就是可以同时存在。