在Swift中結構體和枚舉也能夠定義方法,而在 Objective-C 中,類是唯一能定義方法的類型。 實例方法 實例方法是屬於某個特定類、結構體或者枚舉類型實例的方法,實例方法提供訪問和修改實例屬性的途徑,實例方法的語法與函數完全一致。實例方法能夠隱式訪問它所屬類型的所有的其他實例方法和屬性。實例 ...
在Swift中結構體和枚舉也能夠定義方法,而在 Objective-C 中,類是唯一能定義方法的類型。
實例方法
實例方法是屬於某個特定類、結構體或者枚舉類型實例的方法,實例方法提供訪問和修改實例屬性的途徑,實例方法的語法與函數完全一致。實例方法能夠隱式訪問它所屬類型的所有的其他實例方法和屬性。實例方法只能被它所屬的類的某個特定實例調用。實例方法不能脫離於現存的實例而被調用。
class Counter { var count = 0 func increment() { count++ } func incrementBy(amount: Int) { count += amount } func reset() { count = 0 } }
和調用屬性一樣,用點語法(dot syntax)調用實例方法
方法的局部參數名稱和外部參數名稱
Swift 預設僅給方法的第一個參數名稱一個局部參數名稱;預設同時給第二個和後續的參數名稱局部參數名稱和外部參數名稱。這個約定與典型的命名和調用約定相適應,與你在寫 Objective-C 的方法時很相似。這個約定還讓表達式方法在調用時不需要再限定參數名稱。
下麵Counter的另外寫法
class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { count += amount * numberOfTimes } }
incrementBy方法有兩個參數: amount和numberOfTimes。預設情況下,Swift 只把amount當作一個局部名稱,但是把numberOfTimes即看作局部名稱又看作外部名稱。下麵調用這個方法:
let counter = Counter() counter.incrementBy(5, numberOfTimes: 3) // counter value is now 15你不必為第一個參數值再定義一個外部變數名:因為從函數名incrementBy已經能很清楚地看出它的作用。但是第二個參數,就要被一個外部參數名稱所限定,以便在方法被調用時明確它的作用。 這種預設的行為能夠有效的處理方法(method),類似於在參數numberOfTimes前寫一個井號(#):
func incrementBy(amount: Int, #numberOfTimes: Int) { count += amount * numberOfTimes }
這種預設行為使上面代碼意味著:在 Swift 中定義方法使用了與 Objective-C 同樣的語法風格,並且方法將以自然表達式的方式被調用。
修改方法的外部參數名稱行為
你可以自己添加一個顯式的外部名稱或者用一個井號(#)作為第一個參數的首碼來把這個局部名稱當作外部名稱使用。 相反,如果你不想為方法的第二個及後續的參數提供一個外部名稱,可以通過使用下劃線(_)作為該參數的顯式外部名稱,這樣做將覆蓋預設行為。
self屬性
類型的每一個實例都有一個稱為“self”的隱式屬性,它與實例本身相當。你可以在一個實例的實例方法中使用這個隱含的self屬性來引用當前實例。
上面例子中的increment方法還可以這樣寫
func increment() { self.count++ }
你不必在你的代碼裡面經常使用self。Swift 假定你是指當前實例的屬性或者方法。這種假定在上面的Counter中已經示範了:Counter中的三個實例方法中都使用的是count(而不是self.count)
在實例方法的某個參數名稱與實例的某個屬性名稱相同的時候,優先參數名,所以在引用屬性時必須使用一種更嚴格的方式。這時你可以使用self屬性來區分參數名稱和屬性名稱。下麵的例子中,self消除方法參數x和實例屬性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") } // 輸出 "This point is to the right of the line where x == 1.0"(這個點在x等於1.0這條線的右邊)
如果不使用self首碼,Swift 就認為兩次使用的x都指的是名稱為x的函數參數
在實例方法中修改值類型
結構體和枚舉是值類型。一般情況下,值類型的屬性不能在它的實例方法中被修改。但是,如果你確實需要在某個具體的方法中修改結構體或者枚舉的屬性,你可以選擇mutating關鍵字修飾實例方法,然後方法就可以從方法內部改變它的屬性;並且它做的任何改變在方法結束時還會保留在原始結構中。方法還可以給它隱含的self屬性賦值一個全新的實例,這個新實例在方法結束後將替換原來的實例。將關鍵字mutating 放到方法的func關鍵字之前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) println("The point is now at (\(somePoint.x), \(somePoint.y))") // 輸出 "The point is now at (3.0, 4.0)"
註意:不能在結構體類型常量上調用變異方法,因為常量的屬性不能被改變,即使想改變的是常量的變數屬性也不行,
在變異方法中給self賦值(Assigning to self Within a Mutating Method) mutating方法能夠賦給隱含屬性self一個全新的實例。上面Point的例子可以用下麵的方式改寫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 現在等於 .High ovenLight.next() // ovenLight 現在等於 .Off
上面的例子中定義了一個三態開關的枚舉。每次調用next方法時,開關在不同的電源狀態(Off,Low,High)之前迴圈切換。
類型方法 聲明類的類型方法,在方法的func關鍵字之前加上關鍵字class;聲明結構體和枚舉的類型方法,在方法的func關鍵字之前加上關鍵字static。 註意:在 Objective-C 裡面,你只能為 Objective-C 的類定義類型方法(type-level methods)。在 Swift 中,你可以為所有的類、結構體和枚舉定義類型方法:每一個類型方法都被它所支持的類型顯式包含 類型方法和實例方法一樣用點語法調用class SomeClass { class func someTypeMethod() { // type method implementation goes here } } SomeClass.someTypeMethod()
在類型方法的方法體(body)中,self指向這個類型本身,而不是類型的某個實例。對於結構體和枚舉來說,這意味著你可以用self來消除靜態屬性和靜態方法參數之間的歧義 一般來說,任何未限定的方法和屬性名稱,將會來自於本類中另外的類型級別的方法和屬性。一個類型方法可以調用本類中另一個類型方法的名稱,而無需在方法名稱前面加上類型名稱的首碼。同樣,結構體和枚舉的類型方法也能夠直接通過靜態屬性的名稱訪問靜態屬性,而不需要類型名稱首碼。