您的位置:首页 > 移动开发 > Swift

Swift2.1 语法指南——方法

2015-10-12 10:51 399 查看
原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html#//apple_ref/doc/uid/TP40014097-CH15-ID234

1、方法

方法是和特定类型关联的函数。类、结构体和枚举都能定义实例方法,也能定义类型方法。

2、实例方法

实例方法属于类、结构体或枚举的实例,它们提供实例的功能实现,或者是访问和修改属性的值,或者是提供实例目的相关的功能。实例方法的语法和函数一样。

实例方法只能被它所属的类的某个实例调用。实例方法不能脱离于现存的实例而被调用。

class Counter {
var count = 0
func increment() {
++count
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}


实例方法的调用与属性相同:

let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1
counter.incrementBy(5)
// the counter's value is now 6
counter.reset()
// the counter's value is now 0


3、方法的局部参数名和外部参数名

方法参数与函数参数一样,可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用)(因为方法就是函数,只是这个函数与某个类型相关联了):

class Counter {
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes: Int) {
count += amount * numberOfTimes
}
}


方法的调用:

let counter = Counter()
counter.incrementBy(5, numberOfTimes: 3)
// counter value is now 15


你不必为第一个参数值再定义一个外部变量名:因为从函数名
incrementBy(_numberOfTimes:)
已经能很清楚地看出它的作用。但是第二个参数,就要被一个外部参数名称所限定,以便在方法被调用时明确它的作用。 这种默认行为使上面代码意味着:在 Swift 中定义方法使用了与 Objective-C 同样的语法风格,并且方法将以自然表达式的方式被调用。

(1)外部参数名的更改

可以自己添加一个显式的外部名称作为第一个参数的前缀来把这个局部名称当作外部名称使用。

相反,如果你不想为方法的第二个及后续的参数提供一个外部名称,可以通过使用下划线(
_
)作为该参数的显式外部名称。

4、self属性

每一个类型的实例都有一个隐式的属性self,self完全等同于实例本身。

可以在实例的方法中用self作为实例本身的引用。

func increment() {
self.count++
}


实际上,不必显式地写self。如果你在方法中使用已知的属性或方法时不显式地写self,Swift会认为你使用的是当前实例的属性或方法。因此,在上述方法中可以用count而不是self.count。

当方法的参数名和实例的属性同名时,这种规则会导致异常。这种情况下,就有必要使用self来区分参数名和属性名。

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")
}
// prints "This point is to the right of the line where x == 1.0"


5、在实例方法中修改值类型

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

然而,如果你需要在实例方法中修改结构体或枚举属性,你可以选择将这个方法变异(mutating),这样,就可以在方法内部修改属性,并且任何改变都会在方法结束后保留在原始结构体中。这种方法也可以将一个新的实例赋值给self属性,方法结束后,这个新的实例会替换旧的实例。

方法定义时加上
mutating
关键字,这才让方法可以修改值类型的属性:

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))")
// prints "The point is now at (3.0, 4.0)"


注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行。

let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0)
// this will report an error


6、在mutating方法中赋值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)
}
}


上述的变异方法
moveByX(_:y:)
创建了一个新的结构(它的 x 和 y 的值都被设定为目标值)。它的效果与之前的是一致的。

枚举的变异方法可以把
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 is now equal to .High
ovenLight.next()
// ovenLight is now equal to .Off


7、类型方法

实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,称为类型方法。

声明结构体和枚举的类型方法,在方法的
func
关键字之前加上关键字
static
。类可以用关键字
class
来允许子类重写父类的实现方法。

类型方法的调用:

class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()


类型方法中的self等价于类型本身,而不也是等价于类型的实例。对于结构体和枚举而言,你可以用self来区分类型属性和类型方法参数。

一般来说,在类方法中,任何没有用self限定的方法和属性名称,将会来自于本类中其他的类型级别的方法和属性。类型方法可以直接用其他类型方法的名字来调用它们,不必加上类型名。类似地,枚举和结构体的类型属性里也可以直接用其他类型属性的名字来访问。

下面的例子定义了一个名为
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
}
}
}


LevelTracker
监测玩家的已解锁的最高等级。这个值被存储在类型属性
highestUnlockedLevel
中。

LevelTracker
还定义了两个类型方法与
highestUnlockedLevel
配合工作。第一个类型方法是
unlockLevel
:一旦新等级被解锁,它会更新
highestUnlockedLevel
的值。第二个类型方法是
levelIsUnlocked
:如果某个给定的等级已经被解锁,它将返回
true
。(注意:尽管我们没有使用类似
LevelTracker.highestUnlockedLevel
的写法,这个类型方法还是能够访问类型属性
highestUnlockedLevel


除了类型属性和类型方法,
LevelTracker
还监测每个玩家的进度。它用实例属性
currentLevel
来监测玩家当前的等级。

为了便于管理
currentLevel
属性,
LevelTracker
定义了实例方法
advanceToLevel
。这个方法会在更新
currentLevel
之前检查所请求的新等级是否已经解锁。
advanceToLevel
方法返回布尔值以指示是否能够设置
currentLevel


下面,来使用这个结构体:

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
}
}


Player
类创建一个新的
LevelTracker
实例来监测这个用户的进度。它提供了
completedLevel
方法:一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了
advanceToLevel
返回的布尔值,因为之前调用
LevelTracker.unlockLevel
时就知道了这个等级已经被解锁了)。

你还可以为一个新的玩家创建一个
Player
的实例,让玩家完成等级一:

var player = Player(name: "Argyrios")
player.completedLevel(1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// prints "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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: