方法(Methods)
知识点:
1、方法的定义和使用;
2、方法的内部参数名和外部参数名;
3、类实例中的self说明;
4、变异(mutating)关键字;
5、类型方法实例;
方法是与某些特定类型相关联的函数。
结构体和枚举能够定义方法是 Swift 与 C/Objective-C 的主要区别之一。
实例方法 (Instance Methods)
实例方法是属于某个特定类、结构体或者枚举类型实例的方法。实例方法要写在它所属的类型的前后大括号之间。
例如:下面的例子,定义一个很简单的Counter类,Counter能被用来对一个动作发生的次数进行计数:
class Counter {
var count = 0//可变属性count
func increment() {
++count
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
调用:
let counter = Counter()
// 初始计数值是0
counter.increment()
// 计数值现在是1
counter.incrementBy(5)
// 计数值现在是6
counter.reset()
// 计数值现在是0
方法的局部参数名称和外部参数名称
函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用)。
实例:
class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes: Int) {
count += amount * numberOfTimes
}
}
调用
let counter = Counter()
counter.incrementBy(5, numberOfTimes: 3)//这里要声明外部参数名才可以使用,好奇葩的感觉,因为在写代码的时候,如果你不加编译就会报错,不给你通过
// counter 的值现在是 15
解释:
你不必为第一个参数值再定义一个外部变量名:因为从函数名incrementBy(_numberOfTimes:)已经能很清楚地看出它的作用。但是第二个参数,就要被一个外部参数名称所限定,以便在方法被调用时明确它的作用。(这里我很想不明白,为什么还要一个外部参数名来修饰它,这不是默认第一个实参对应第一个行参的吗?何必多此一举呢???)
在每个类中,都有一个self属性。这个很好理解,你就当它是java中的this。就完了。
用处:在方法参数名和属性同名时使用。因为在方法中,参数名具有优先级高(因为近嘛)。所以需要额外指明。
swift允许动态修改实例的结构体和属性。要使用关键字 变异(mutating)来修饰方法。并且它做的任何改变在方法结束时还会保留在原始结构中。
要使用变异方法, 将关键字mutating 放到方法的func关键字之前就可以了:
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)//x,y初始值
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)”
方法还可以给它隐含的self属性赋值一个全新的实例,这个新实例在方法结束后将替换原来的实例。
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)//这里返回一个Point实例
}
}
var somePoint = Point(x: 1.0, y: 1.0)//somePoint是self返回的的新的实例,同时初始化了x,y
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)”
枚举的变异方法可以把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
上面的例子中定义了一个三态开关的枚举。每次调用next方法时,开关在不同的电源状态(Off,Low,High)之前循环切换。
这里又个很好的官方例子,慢慢走一遍程序,你就懂得了。这里是地址:swift中文学习地址
下面的例子定义了一个名为LevelTracker结构体。它监测玩家的游戏发展情况(游戏的不同层次或阶段)。这是一个单人游戏,但也可以存储多个玩家在同一设备上的游戏信息。
游戏初始时,所有的游戏等级(除了等级 1)都被锁定。每次有玩家完成一个等级,这个等级就对这个设备上的所有玩家解锁。LevelTracker结构体用静态属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级
struct LevelTracker {
static var highestUnlockedLevel = 1
static func unlockLevel(level: Int) {//解锁给定等级
if level > highestUnlockedLevel { highestUnlockedLevel = level }
}
static func levelIsUnlocked(level: Int) -> Bool {//检查是当前等级被解锁
return level <= highestUnlockedLevel
}
var currentLevel = 1
mutating func advanceToLevel(level: Int) -> Bool {//检查所请求的新等级是否已经解锁
if LevelTracker.levelIsUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
下面,Player类使用LevelTracker来监测和更新每个玩家的发展进度:
class Player {
var tracker = LevelTracker()
let playerName: String
func completedLevel(level: Int) {
LevelTracker.unlockLevel(level + 1)
tracker.advanceToLevel(level + 1)
}
init(name: String) {
playerName = name
}
}
调用
var player = Player(name: "Argyrios")
player.completedLevel(1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// 打印输出:highest unlocked level is now 2
如果你创建了第二个玩家,并尝试让他开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败:
player = Player(name: "Beto")
if player.tracker.advanceToLevel(6) {
print("player is now on level 6")
} else {
print("level 6 has not yet been unlocked")
}
// 打印输出:level 6 has not yet been unlocked
以上大多是借鉴,加入了不少自己的理解和看法。