指南:方法(Methods)

  • 方法是與某些特定類型相關(guān)聯(lián)的函數(shù)。
  • 結(jié)構(gòu)體和枚舉能夠定義方法是 Swift 與 C/Objective-C 的主要區(qū)別之一。

實例方法 (Instance Methods)

  • 實例方法是屬于某個特定類、結(jié)構(gòu)體或者枚舉類型實例的方法。需要先創(chuàng)建實例,然后通過這個實例再去訪問實例方法。
  • 和調(diào)用屬性一樣,用點語法(dot syntax)調(diào)用實例方法。
  • 類型的每一個實例都有一個隱含屬性叫做self,self完全等同于該實例本身。
  • 不必在代碼里面經(jīng)常寫self。不論何時,只要在一個方法中使用一個已知的屬性或者方法名稱,如果沒有明確地寫self,Swift 假定是指當前實例的屬性或者方法。
  • 當實例方法的某個參數(shù)名稱與實例的某個屬性名稱相同的時候,參數(shù)名稱享有優(yōu)先權(quán)。這時可以使用self屬性來區(qū)分參數(shù)名稱和屬性名稱。
  • 結(jié)構(gòu)體和枚舉是值類型。默認情況下,值類型的屬性不能在它的實例方法中被修改。
  • 要使用可變方法,將關(guān)鍵字mutating 放到方法的func關(guān)鍵字之前就可以了。
  • 可變方法能夠賦給隱含屬性self一個全新的實例。
  • 不能在結(jié)構(gòu)體類型的常量(a constant of structure type)上調(diào)用可變方法,因為其屬性不能被改變,即使屬性是變量屬性。
struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOfX(x: Double) -> Bool {
        return self.x > x  // 如果不使用self前綴,Swift 就認為兩次使用的x都指的是名稱為x的函數(shù)參數(shù)。
    }
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
 //       x += deltaX
 //       y += deltaY   // 改屬性
        self = Point(x: x + deltaX, y: y + deltaY) // 該實例本身
    }
}
var 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

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)"
  • 枚舉的可變方法可以把self設(shè)置為同一枚舉類型中不同的成員:
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 現(xiàn)在等于 .High
ovenLight.next()
// ovenLight 現(xiàn)在等于 .Off
  • 從外部直接設(shè)屬性很方便,當然struct和enum本身是var的。但是通過方法修改函數(shù)卻比較麻煩,需要額外標注mutating關(guān)鍵字。
  • 實際使用中,struct和enum盡量作為數(shù)據(jù)結(jié)構(gòu),作為類的屬性。行為定義的事情還是交給類來做
  • 盡量減少mutating的使用,用方法修改屬性的事情盡量少做。可以增加計算屬性來達到相同的效果
  • struct和enum修改self,形成新實例,成為新成員的方式可以多用用,這在某些特殊場合比較合適。

類型方法 (Type Methods)

  • 在方法的func關(guān)鍵字之前加上關(guān)鍵字static,來指定類型方法。類還可以用關(guān)鍵字class來允許子類重寫父類的方法實現(xiàn)。
  • 可以為所有的類、結(jié)構(gòu)體和枚舉定義類型方法。每一個類型方法都被它所支持的類型顯式包含。
  • 類型方法和實例方法一樣用點語法調(diào)用。但是,是在類型上調(diào)用這個方法,而不是在實例上調(diào)用。用類型名直接調(diào)用,而不是用實例名。
  • 在類型方法的方法體(body)中,self指向這個類型本身,而不是類型的某個實例。這意味著可以用self來消除類型屬性和類型方法參數(shù)之間的歧義。
  • 類型方法可以直接通過名稱調(diào)用自己的類型方法和類型屬性,而無需在類型方法或者類型屬性名稱前面加上類型名稱。
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
        }
    }
}

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容