在swift當中, 除了類可以定義方法, 結構體和枚舉也可以定義方法, 這是Swift 與 C/Objective-C 的主要區(qū)別之一.
class Counter {
//保持對當前計數(shù)器值的追蹤。
var count = 0
//increment讓計數(shù)器按一遞增
func increment() {
count += 1 //注意. 此處不能使用count++, 在swift3.x里面, 已經(jīng)廢除++, --的寫法
}
//incrementBy(amount: Int)讓計數(shù)器按一個指定的整數(shù)值遞增边酒;
func incrementBy(amount: Int) {
count += amount
}
//reset將計數(shù)器重置為0经柴。
func reset() {
count = 0
}
}
方法的使用, 與OC一樣, 使用, 點語法訪問
let counter = Counter()
// 初始計數(shù)值是0
counter.increment()
// 計數(shù)值現(xiàn)在是1
counter.incrementBy(amount: 5) //swift3.x寫法
//counter.incrementBy(5) , swift2.x寫法
// 計數(shù)值現(xiàn)在是6
counter.reset()
// 計數(shù)值現(xiàn)在是0
self屬性
類型的每一個實例都有一個隱含屬性叫做self,self完全等同于該實例本身墩朦。你可以在一個實例的實例方法中使用這個隱含的self屬性來引用當前實例坯认。
上面例子中的increment方法還可以這樣寫:
func increment() {
self.count++
}
實際上,你不必在你的代碼里面經(jīng)常寫self氓涣。不論何時牛哺,只要在一個方法中使用一個已知的屬性或者方法名稱,如果你沒有明確的寫self春哨,Swift 假定你是指當前實例的屬性或者方法荆隘。這種假定在上面的Counter中已經(jīng)示范了:Counter中的三個實例方法中都使用的是count(而不是self.count)。
使用這條規(guī)則的主要場景是實例方法的某個參數(shù)名稱與實例的某個屬性名稱相同的時候赴背。在這種情況下椰拒,參數(shù)名稱享有優(yōu)先權,并且在引用屬性時必須使用一種更嚴格的方式凰荚。這時你可以使用self屬性來區(qū)分參數(shù)名稱和屬性名稱燃观。
在實例方法中修改值類型
mutating方法(變異方法)
結構體和枚舉是值類型。一般情況下便瑟,值類型的屬性不能在它的實例方法中被修改缆毁。
如果你確實需要在某個具體的方法中修改結構體或者枚舉的屬性,你可以選擇變異(mutating)這個方法到涂,然后方法就可以從方法內(nèi)部改變它的屬性脊框;并且它做的任何改變在方法結束時還會保留在原始結構中。方法還可以給它隱含的self屬性賦值一個全新的實例践啄,這個新實例在方法結束后將替換原來的實例浇雹。
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(deltaX: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
//不能用聲明為常量(let)類型的結構體調用變異方法,因為常量的屬性不能被改變屿讽,即使想改變的是常量的變量屬性也不行
let fixedPoint = Point(x: 3.0, y: 3.0) //?正確寫法, 把fixedPoint結構體聲明為var
fixedPoint.moveByX(deltaX: 2.0, y: 3.0) //error -> change 'let' to 'var' to make it mutable
在變異方法中給self賦值(Assigning to self Within a Mutating Method)
上面的例子可以改寫成
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) //創(chuàng)建一個新的結構體, 并把它賦值給自己
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(deltaX: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
枚舉的變異方法
//枚舉的變異方法可以把self設置為相同的枚舉類型中不同的成員:
enum TriStateSwitch {
case Off, Low, High
mutating func next() {
switch self {
case .Off: // case時別忘記使用(.)運算符, 否則 error: enum element 'Off' cannot be referenced as an instance member
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
類型方法(Type Methods)
實例方法是被類型的某個實例調用的方法昭灵。你也可以定義類型本身調用的方法,這種方法就叫做類型方法伐谈。聲明類的類型方法烂完,在方法的func關鍵字之前加上關鍵字class;聲明結構體和枚舉的類型方法诵棵,在方法的func關鍵字之前加上關鍵字static抠蚣。
//類型方法和實例方法一樣用點語法調用。但是履澳,你是在類型層面上調用這個方法嘶窄,而不是在實例層面上調用
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
//在類型方法的方法體(body)中缓屠,self指向這個類型本身,而不是類型的某個實例护侮。對于結構體和枚舉來說敌完,這意味著你可以用self來消除靜態(tài)屬性和靜態(tài)方法參數(shù)之間的歧義(類似于我們在前面處理實例屬性和實例方法參數(shù)時做的那樣)。
}
}
SomeClass.someTypeMethod()
//一般來說羊初,任何未限定的方法和屬性名稱滨溉,將會來自于本類中另外的類型級別的方法和屬性。一個類型方法可以調用本類中另一個類型方法的名稱长赞,而無需在方法名稱前面加上類型名稱的前綴晦攒。同樣,結構體和枚舉的類型方法也能夠直接通過靜態(tài)屬性的名稱訪問靜態(tài)屬性得哆,而不需要類型名稱前綴脯颜。