Xcode 11.3.1
Swift 5.1.3
方法是与某些特定类型相关联的函数。
实例方法为给定类型的实例封装了具体的任务与功能;类型方法与类型本身相关联。类型方法与 Objective-C 中的类方法(class methods)相似。
实例方法是属于某个特定类、结构体或者枚举类型实例的方法。
实例方法有以下特点:
class Counter {
var count = 0
func increment() {
count += 1
printSelf()
}
func increment(by amount: Int) {
count += amount
printSelf()
}
func reset() {
count = 0
printSelf()
}
func printSelf() {
print("count = \(count)")
}
}
let counter = Counter()
counter.increment()
counter.increment(by: 2)
counter.reset()
/**
count = 1
count = 3
count = 0
*/
以上示例中, 访问属性/方法都使用了隐式调用.
类型的每一个实例都有一个隐含属性叫做self, self 完全等同于该实例本身. 你可以在一个实例的实例方法中使用这个隐含的 self 属性来引用当前实例.
之所以说上面示例中为隐式调用, 是因为其使用了隐含的self属性.
完整写法 (显式调用) 为:
func increment() {
self.count += 1
self.printSelf()
}
虽然我们可以简略self, 但是在某些情况下我们还是需要使用显式写法.
例如, 以上示例中, 把方法 increment(by amount: Int) 中 amount 改成 count, 那么结果就不是我们想要的. 因为参数count优先级大于存储属性count, 而我们希望的是对存储属性count进行计算.
那么就需要使用self, 其效果是一致的:
func increment(by count: Int) {
self.count += count
printSelf()
}
在之前的函数章节中, 我们有讨论过参数标签和参数名称.
在本章节中, 因为涉及方法的调用, 我们将参数标签改称为外部参数名称, 将参数名称改为局部参数名称.
Swift 函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用)。
像在 Objective-C 中一样,Swift 中方法的名称通常用一个介词指向方法的第一个参数,比如:with,for,by等等。
在第一个示例中, by 为外部参数名称, amount 为局部参数名称
func increment(by amount: Int) {
count += amount
printSelf()
}
counter.increment(by: 2)
我们也可以使用下划线"_"来取代外部参数名称, 这样在调用方法时就没有了外部参数名称 (参数标签) :
func increment(_ count: Int) {
self.count += count
printSelf()
}
counter.increment(2)
Swift 语言中结构体和枚举是值类型。一般情况下,值类型的属性不能在它的实例方法中被修改。
例如:
struct Size {
var width = 10
var height = 20
// 以下方法报错
func increment(by amount: Int) {
width += amount;
height += amount;
}
}
但是,如果你确实需要在某个具体的方法中修改结构体或者枚举的属性,你可以选择变异(mutating)这个方法,然后方法就可以从方法内部改变它的属性;方法还可以给它隐含的 self 属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。
例如:
struct Size {
var width = 10
var height = 20
mutating func increment(by amount: Int) {
width += amount;
height += amount;
}
}
var size = Size()
print("\(size)")
// Size(width: 10, height: 20)
size.increment(by: 5)
print("\(size)")
// Size(width: 15, height: 25)
上面示例中, 可以改写成如下, 得到的结果是一样的:
struct Size {
var width = 10
var height = 20
mutating func increment(by amount: Int) {
// width += amount;
// height += amount;
self = Size(width: width+amount, height: height+amount)
}
}
枚举的可变方法可以把 self 设置为同一枚举类型中不同的成员:
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
// ovenLight 现在等于 .high
ovenLight.next()
// ovenLight 现在等于 .off
实例方法被某个类型的实例调用。
类型方法被类型本身调用。
声明结构体和枚举的类型方法,在方法的func关键字之前加上关键字static。
类可能会用关键字class来允许子类重写父类的实现方法。
class Math {
class func abs(number: Int) -> Int {
if number < 0 {
return (-number)
}else {
return number
}
}
}
struct Sample {
static func abs(number: Int) -> Int {
if number < 0 {
return (-number)
}else {
return number
}
}
}
let number1 = Math.abs(number: -5)
let number2 = Sample.abs(number: -10)
print(number1)
print(number2)
/**
5
10
*/