實(shí)例方法是被類型的某個(gè)實(shí)例調(diào)用的方法。你也可以定義類型本身調(diào)用的方法,這種方法就叫做類型方法。聲明類的類型方法,在方法的func關(guān)鍵字之前加上關(guān)鍵字class;聲明結(jié)構(gòu)體和枚舉的類型方法,在方法的func關(guān)鍵字之前加上關(guān)鍵字static。
注意:
在 Objective-C 里面,你只能為 Objective-C 的類定義類型方法(type-level methods)。在 Swift 中,你可以為所有的類、結(jié)構(gòu)體和枚舉定義類型方法:每一個(gè)類型方法都被它所支持的類型顯式包含。
類型方法和實(shí)例方法一樣用點(diǎn)語法調(diào)用。但是,你是在類型層面上調(diào)用這個(gè)方法,而不是在實(shí)例層面上調(diào)用。下面是如何在SomeClass類上調(diào)用類型方法的例子:
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
在類型方法的方法體(body)中,self指向這個(gè)類型本身,而不是類型的某個(gè)實(shí)例。對(duì)于結(jié)構(gòu)體和枚舉來說,這意味著你可以用self來消除靜態(tài)屬性和靜態(tài)方法參數(shù)之間的歧義(類似于我們?cè)谇懊嫣幚韺?shí)例屬性和實(shí)例方法參數(shù)時(shí)做的那樣)。
一般來說,任何未限定的方法和屬性名稱,將會(huì)來自于本類中另外的類型級(jí)別的方法和屬性。一個(gè)類型方法可以調(diào)用本類中另一個(gè)類型方法的名稱,而無需在方法名稱前面加上類型名稱的前綴。同樣,結(jié)構(gòu)體和枚舉的類型方法也能夠直接通過靜態(tài)屬性的名稱訪問靜態(tài)屬性,而不需要類型名稱前綴。
下面的例子定義了一個(gè)名為LevelTracker結(jié)構(gòu)體。它監(jiān)測(cè)玩家的游戲發(fā)展情況(游戲的不同層次或階段)。這是一個(gè)單人游戲,但也可以存儲(chǔ)多個(gè)玩家在同一設(shè)備上的游戲信息。
游戲初始時(shí),所有的游戲等級(jí)(除了等級(jí) 1)都被鎖定。每次有玩家完成一個(gè)等級(jí),這個(gè)等級(jí)就對(duì)這個(gè)設(shè)備上的所有玩家解鎖。LevelTracker結(jié)構(gòu)體用靜態(tài)屬性和方法監(jiān)測(cè)游戲的哪個(gè)等級(jí)已經(jīng)被解鎖。它還監(jiān)測(cè)每個(gè)玩家的當(dāng)前等級(jí)。
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監(jiān)測(cè)玩家的已解鎖的最高等級(jí)。這個(gè)值被存儲(chǔ)在靜態(tài)屬性highestUnlockedLevel中。
LevelTracker還定義了兩個(gè)類型方法與highestUnlockedLevel配合工作。第一個(gè)類型方法是unlockLevel:一旦新等級(jí)被解鎖,它會(huì)更新highestUnlockedLevel的值。第二個(gè)類型方法是levelIsUnlocked:如果某個(gè)給定的等級(jí)已經(jīng)被解鎖,它將返回true。(注意:盡管我們沒有使用類似LevelTracker.highestUnlockedLevel的寫法,這個(gè)類型方法還是能夠訪問靜態(tài)屬性highestUnlockedLevel)
除了靜態(tài)屬性和類型方法,LevelTracker還監(jiān)測(cè)每個(gè)玩家的進(jìn)度。它用實(shí)例屬性currentLevel來監(jiān)測(cè)玩家當(dāng)前的等級(jí)。
為了便于管理currentLevel屬性,LevelTracker定義了實(shí)例方法advanceToLevel。這個(gè)方法會(huì)在更新currentLevel之前檢查所請(qǐng)求的新等級(jí)是否已經(jīng)解鎖。advanceToLevel方法返回布爾值以指示是否能夠設(shè)置currentLevel。
下面,Player類使用LevelTracker來監(jiān)測(cè)和更新每個(gè)玩家的發(fā)展進(jìn)度:
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類創(chuàng)建一個(gè)新的LevelTracker實(shí)例來監(jiān)測(cè)這個(gè)用戶的發(fā)展進(jìn)度。它提供了completedLevel方法:一旦玩家完成某個(gè)指定等級(jí)就調(diào)用它。這個(gè)方法為所有玩家解鎖下一等級(jí),并且將當(dāng)前玩家的進(jìn)度更新為下一等級(jí)。(我們忽略了advanceToLevel返回的布爾值,因?yàn)橹罢{(diào)用LevelTracker.unlockLevel時(shí)就知道了這個(gè)等級(jí)已經(jīng)被解鎖了)。
你還可以為一個(gè)新的玩家創(chuàng)建一個(gè)Player的實(shí)例,然后看這個(gè)玩家完成等級(jí)一時(shí)發(fā)生了什么:
var player = Player(name: "Argyrios")
player.completedLevel(1)
println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// 輸出 "highest unlocked level is now 2"(最高等級(jí)現(xiàn)在是2)
如果你創(chuàng)建了第二個(gè)玩家,并嘗試讓它開始一個(gè)沒有被任何玩家解鎖的等級(jí),那么這次設(shè)置玩家當(dāng)前等級(jí)的嘗試將會(huì)失敗:
player = Player(name: "Beto")
if player.tracker.advanceToLevel(6) {
println("player is now on level 6")
} else {
println("level 6 has not yet been unlocked")
}
// 輸出 "level 6 has not yet been unlocked"(等級(jí)6還沒被解鎖)