天天看點

Swift學習筆記(九)方法

方法

類、結構體和枚舉都能定義成執行個體方法和類方法

Swift與C和Objective-C的主要差別就是結構體和枚舉可以定義方法。在Objective-C中,隻有類才能定義方法。而在Swift中,你可以有選擇性的在類、結構體或枚舉中定義方法,并且使得在你建立的類中定義方法時更具有靈活性。

執行個體方法

執行個體方法是屬于一個特定的類、結構體或枚舉的執行個體的函數,一個執行個體方法具有隐式通路所有其他的執行個體方法和屬性類型

class Counter {
    var count = 0
    func increment() {
        ++count
    }
    func incrementBy(amount: Int) {
        count += amount
    }
    func reset() {
        count = 0
    }
}
//Counter類裡定義了三個執行個體方法:
//increment 計數器增量加1
//incrementBy(amount: Int)計數器由特定的整數作為增量
//reset 重置計數器的值為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
           

方法的局部和外部參數名

函數的參數可以擁有局部名稱(在函數體内使用)和一個外部名稱(在調用函數時使用)。

方法的參數也是如此,因為方法是與類型相關的函數。然而,局部名稱和外部名稱的預設行為是不同于函數和方法的。

Swift在方法中預設的将第一個參數名作為方法的局部參數名,也預設的将第二個和後續的參數名同時作為局部參數和外部參數名

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

這個incrementBy方法有兩個參數amount 和 numberOfTimes.預設情況下,Swift将amount視為唯一的局部名稱,但将numberOfTimes同時視為局部名稱和外部名稱。調用方法如下:

let counter2 = Counter2()
counter2.incrementBy(5, numberOfTimes: 3)
// counter value is now 15
//若在參數名前加#則表示使用與OC相同的文法風格,将參數名同時作為外部參數名和内部參數名
func incrementBy(#amount: Int, numberOfTimes: Int) {
    int count += amount * numberOfTimes
}
//counter2.incrementBy(amount:5, numberOfTimes: 3)
//方法的外部參數名稱修飾行為
//有時為方法的第一個參數提供一個外部參數名是非常有用的。盡管這不是預設的行為。你可以添加一個你自己明确的外部名稱,或者你也可以使用局部名稱作為外部名稱并在參數名前加一個散列符号作為參數名的字首
//相反的,如果你不想為一個方法的第二個參數或後續參數提供外部參數名,可通過使用下劃線符号(_)作為該參數的顯式外部參數名稱來覆寫預設行為。
           

self屬性

每一個類型的執行個體都有一個稱為 self 的隐式屬性,它是完全等同于該實體本身的。你可以使用這個隐式的self屬性飲用目前執行個體的執行個體方法。

主要的異常發生在一個執行個體方法的參數名和執行個體的屬性名相同。在這種情況下,參數名優先,有必要參考屬性更多的合格方式。你可以使用隐式的self屬性區分參數名和屬性名

在這裡,使用了self來區分名稱同為x的方法參數和一個執行個體屬性:

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) {
 println("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"
           

修改值類型的執行個體方法

結構體和枚舉都是值類型。預設情況下,值類型的屬性不能從它的内部執行個體方法修改。

如果你需要在一個特定的方法中修改你的結構體或枚舉的屬性,你可以在這個方法中選擇加入變異行為

struct Point {
    var x = 0.0, y = 0.0
//    mutating關鍵字添加到方法的定義上,使它能夠修改它的屬性
    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)
println("The point is now at ((somePoint.x), (somePoint.y))")
// prints "The point is now at (3.0, 4.0)"
           

由變異方法配置設定self

變異方法可以配置設定一個全新的執行個體給隐式的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)
    }
}
           

枚舉的變異方法可以在同一個枚舉裡為隐式的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
           

類型方法

由類型自身調用的方法,稱為類型方法

你可以通過在func 關鍵字前寫上class 關鍵字來聲明類的類型方法,而在結構體或枚舉内定義類型方法則需在func關鍵字前書寫static 關鍵字來聲明

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

在類型方法體内,隐式的self屬性引用類型本身,而不是該類型的一個執行個體。對于 結構體和枚舉,這意味着你可以使用self來消除靜态你操作靜态屬性、靜态方法參數和執行個體屬性和執行個體方法參數的歧義。

一個類型方法可以通過其它的方法名來調用另一個類型方法,而不需要為類型名加字首。同樣,結構體和枚舉的類型方法也能通過使用靜态屬性名通路靜态屬性,而不需要類型名做字首。

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