Swift之方法

在Swift中不仅类可以定义实例方法和类型方法,结构体和枚举类型也可以定义实例方法和类型方法。这是Swift和Objective-C之间的只要区别之一。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}

let counter = Counter()
// 初始计数值是0
counter.increment()
// 计数值现在是1
counter.increment(by: 5)
// 计数值现在是6
counter.reset()
// 计数值现在是0

上面的increment方法还可以写成:

1
2
3
func increment() {
self.count += 1
}

不必在你的代码里面经常写self。不论何时,只要在一个方法中使用一个已知的属性或者方法名称,如果你没有明确地写self,Swift 假定你是指当前实例的属性或者方法。

使用这条规则的主要场景是实例方法的某个参数名称与实例的某个属性名称相同的时候。在这种情况下,参数名称享有优先权,并且在引用属性时必须使用一种更严格的方式。这时你可以使用self属性来区分参数名称和属性名称。

1
2
3
4
5
6
7
8
9
10
11
12
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOfX(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOfX(1.0) {
print("This point is to the right of the line where x == 1.0")
}
// 打印 "This point is to the right of the line where x == 1.0"

如果不使用self前缀,Swift就认为两次使用的x都指的是名称为x的函数参数。

在实例方法中修改值类型

结构体和枚举都是值类型,值类型的属性是不能在实例方法中修改的。

如果你确实需要在某个特定的方法中修改结构体或者枚举的属性,你可以为这个方法选择可变(mutating)行为,然后就可以从其方法内部改变它的属性;并且这个方法做的任何改变都会在方法执行结束时写回到原始结构中。方法还可以给它隐含的self属性赋予一个全新的实例,这个新实例在方法结束时会替换现存实例。

1
2
3
4
5
6
7
8
9
10
11
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// 打印 "The point is now at (3.0, 4.0)"

上面的Point结构体定义了一个可变方法moveByX(_:y:) 来移动Point实例到给定的位置。该方法被调用时修改了这个点,而不是返回一个新的点。方法定义时加上了mutating关键字,从而允许修改属性。

注意,不能在结构体类型的常量(a constant of structure type)上调用可变方法,因为其属性不能被改变,即使属性是变量属性:

1
2
3
let newPoint = Point(x:1.0, y: 2.0)
newPoint.moveByX(3.3, y:4.0)
//这里会出现报错,因为newPoint是个常量,而不是变量
可变方法中给self赋值

在可变方法中可以给隐含属性self赋一个全新的实例:

1
2
3
4
5
6
7
struct Point{
var x = 0, y = 0
mutating func moveByX(x delayX: Double, y delayY: Double){
self = Point(x: x + delayX, y: y + delayY)
}
}

枚举的可变方法可以把self设置为同一枚举类型中不同的成员:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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来允许子类重写父类的方法实现。类型方法也使用点语法来调用。

在类型方法的方法体(body)中,self指向这个类型本身,而不是类型的某个实例。这意味着你可以用self来消除类型属性和类型方法参数之间的歧义(类似于我们在前面处理实例属性和实例方法参数时做的那样)

1
2
3
4
5
6
class SomeClass {
class func someTypeMethod() {
// 在这里实现类型方法
}
}
SomeClass.someTypeMethod()