繼續學習Swift文檔,從上一章節:屬性,咱們學習了Swift屬性相關的內容,如存儲屬性和計算屬性set和get、懶加載、屬性監聽willSet和didSet、屬性包裝@propertyWrapper、全局和局部變量在懶加載上的區別、類屬性等這些內容。如今,咱們學習Swift的方法相關的內容。因爲篇幅較長,這裏分篇來記錄,接下來,Fighting!html
這一章節的內容比較簡單,熟悉的朋友能夠直接跳到下一章節:下標ios
方法是與特定類型關聯的函數。 類,結構體和枚舉均可以定義實例方法,這些實例方法封裝了用於處理給定類型的實例的特定任務和功能。 類,結構體和枚舉也能夠定義與類型自己關聯的類型方法。 類型方法相似於Objective-C中的類方法。swift
結構體和枚舉能夠在Swift中定義方法這一事實與C和Objective-C的主要不一樣之處。 在Objective-C中,類是惟一能夠定義方法的類型。 在Swift中,您能夠選擇是定義類,結構體仍是枚舉,而且仍然能夠靈活地在建立的類型上定義方法。bash
實例方法是屬於特定類,結構體或枚舉的實例的函數。 它們經過提供訪問和修改實例屬性的方式,或經過提供與實例用途相關的功能來支持這些實例的功能。 實例方法具備與函數徹底相同的語法,如函數中所述。app
您能夠在實例方法的所屬類型的大括號內編寫一個實例方法。 實例方法能夠隱式訪問該類型的全部其餘實例方法和屬性。 實例方法只能在其所屬類型的特定實例上調用。 沒有現有實例,就不能單獨地調用它。ide
這是定義一個簡單的Counter類的示例,該類可用於計算操做發生的次數:函數
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
複製代碼
Counter類定義了三個實例方法:post
Counter類還定義了一個count屬性,來跟蹤記錄當前的次數。學習
能夠和調用屬性的方式同樣,用點語法調用實例方法:ui
let counter = Counter()
// the initial counter value is 0
counter.increment()
// the counter's value is now 1 counter.increment(by: 5) // the counter's value is now 6
counter.reset()
// the counter's value is now 0 複製代碼
函數參數能夠具備名稱(供在函數體內使用)和參數標籤(供在調用函數時使用),如Function Argument Labels and Parameter Names中所述。 方法參數也是如此,由於方法只是與類型關聯的函數。
一個類型的每一個實例都有一個稱爲self的隱式屬性,它與該實例自己徹底等效。 您可使用self屬性在其本身的實例方法中引用當前實例。
上例中的increment()方法能夠這樣寫:
func increment() {
self.count += 1
}
複製代碼
實際上,您不須要常常在代碼中編寫自我。 若是您未明確編寫self,則Swift會假設您在方法中使用已知的屬性或方法名稱時,都在引用當前實例的屬性或方法。 在Counter的三個實例方法中使用count(而不是self.count)能夠證實這一假設。
·當實例方法的參數名稱與該實例的屬性名稱相同時,將發生此規則的主要例外。 在這種狀況下,參數名稱優先,所以有必要以更限定的方式引用該屬性。 您可使用self屬性來區分參數名稱和屬性名稱。
在這裏,self消除了方法參數x和實例屬性之間的歧義,該實例參數也稱爲x:
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("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"
複製代碼
若是沒有self前綴,Swift會假設x的兩種用法都引用了稱爲x的方法參數。
結構體和枚舉是值類型。 默認狀況下,不能從其實例方法中修改值類型的屬性。
可是,若是須要在特定方法中修改結構體或枚舉的屬性,則能夠選擇對該方法進行行爲更改。 而後,該方法能夠從方法內部更改(即更改)其屬性,並在方法結束時將其所作的任何更改寫回到原始結構。 該方法還能夠爲其隱式的self屬性分配一個全新的實例,而且該新實例將在方法結束時替換現有實例。
您能夠經過將mutating關鍵字放在該方法的func關鍵字以前來選擇這種行爲:
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"
複製代碼
上面的Point結構體定義了一個可變的moveBy(x:y :)方法,該方法將Point實例移動必定量。 實際上,此方法不是返回新的點,而是修改了在其上被調用的點。 將mutating關鍵字添加到其定義中,以使其可以修改其屬性。
請注意,您不能在結構體類型的常量上調用可變的(mutating)方法,由於它的屬性即便是可變屬性也沒法更改,如「常量結體構實例的存儲屬性」中所述:
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveBy(x: 2.0, y: 3.0)
// this will report an error
複製代碼
可變方法能夠爲隱式的self屬性分配一個全新的實例。 上面顯示的Point示例能夠用如下方式編寫:
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
複製代碼
此版本的mutableBy(x:y :)方法將建立一個新結構體,其x和y值設置爲目標位置。 調用此方法的替代版本的最終結果將與調用早期版本的結果徹底相同。
枚舉的可變方法能夠將隱式self參數設置爲與相同枚舉的不一樣的case:
enum s {
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
複製代碼
本示例定義了三態開關的枚舉。 每次調用next()方法時,開關都會在三種不一樣的電源狀態(關,低和高)之間循環。
如上所述,實例方法是您在特定類型的實例上調用的方法。 您還能夠定義在類型自己上調用的方法。 這些方法稱爲類方法。 您能夠經過在方法的func關鍵字以前寫入static關鍵字來指示類方法。 類能夠改用class關鍵字,以容許子類覆蓋父類對該方法的實現。
注意
在Objective-C中,您只能爲Objective-C類定義類型級別的方法。 在Swift中,您能夠爲全部類,結構體和枚舉定義類型級別的方法。 每一個類方法都明確地限定於它支持的類型。
類方法使用點語法來調用,就像實例方法同樣。 可是,您在類型上而不是在該類型的實例上調用類方法。 在名爲SomeClass的類上調用類方法的方法以下:
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
複製代碼
在類方法的主體內,隱式self屬性是指類型自己,而不是該類型的實例。這意味着您可使用self來區分類型屬性和類方法參數,就像處理實例屬性和實例方法參數同樣。
通常而言,您在類方法主體內使用的任何不符合的方法和屬性名稱都將引用其餘類型級別的方法和屬性。一個類方法可使用另外一個方法的名稱來調用另外一個類方法,而無需在其前面加上類型名稱。一樣,結構體和枚舉上的類方法可使用類型屬性的名稱訪問類型屬性,而無需使用類型名稱前綴。
下面的示例定義了一個稱爲LevelTracker的結構體,該結構體可跟蹤玩家在遊戲的不一樣關卡或階段中的進度。這是一款單人遊戲,但能夠在單個設備上存儲多個玩家的信息。
首次玩遊戲時,全部遊戲級別(除了第一級)都被鎖定。每當玩家完成一個關卡時,設備上的全部玩家都將解鎖該關卡。 LevelTracker結構體使用類型屬性和方法來跟蹤遊戲的哪些級別已解鎖。它還跟蹤單個玩家的當前級別。
struct LevelTracker {
static var highestUnlockedLevel = 1
var currentLevel = 1
static func unlock(_ level: Int) {
if level > highestUnlockedLevel { highestUnlockedLevel = level }
}
static func isUnlocked(_ level: Int) -> Bool {
return level <= highestUnlockedLevel
}
@discardableResult
mutating func advance(to level: Int) -> Bool {
if LevelTracker.isUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
複製代碼
LevelTracker結構體跟蹤全部玩家已解鎖的最高級別。 此值存儲在名爲maximumUnlockedLevel的類型屬性中。
LevelTracker還定義了兩個類型函數,以與highestUnlockedLevel屬性一塊兒使用。 第一個是稱爲unlock(_ :)的類型函數,每當解鎖新級別時,該函數都會更新highestUnlockedLevel的值。 第二個是方便類型的函數,稱爲isUnlocked(_ :),若是特定級別的數字已被解鎖,則返回true。 (請注意,這些類型方法能夠訪問maximumUnlockedLevel類型屬性,而無需將其編寫爲LevelTracker.highestUnlockedLevel。)
除了其類型屬性和類方法以外,LevelTracker還能夠跟蹤單個玩家在遊戲中的進度。 它使用稱爲currentLevel的實例屬性來跟蹤玩家當前正在玩的級別。
爲了幫助管理currentLevel屬性,LevelTracker定義了一個稱爲advance(to :)的實例方法。 在更新currentLevel以前,此方法檢查所請求的新級別是否已被解鎖。 advance(to :)方法返回一個布爾值,以指示它是否實際上可以設置currentLevel。 因爲調用advance(to :)忽略返回值不必定是錯誤的代碼,所以此函數標有@discardableResult屬性。 有關此屬性的更多信息,請參見Attributes。
LevelTracker結構體與Player類一塊兒使用,以下所示,用於跟蹤和更新單個玩家的進度:
class Player {
var tracker = LevelTracker()
let playerName: String
func a(level: Int) {
LevelTracker.unlock(level + 1)
tracker.advance(to: level + 1)
}
init(name: String) {
playerName = name
}
}
複製代碼
Player類建立一個新的LevelTracker實例來跟蹤該玩家的進度。 它還提供了一種稱爲complete(level :)的方法,只要玩家完成特定的關卡,就會調用該方法。 此方法爲全部玩家解鎖下一個級別,並更新玩家的進度以將他們移至下一個級別。 (由於已知該級別已被上一行的LevelTracker.unlock(_ :)調用解鎖,因此會忽略advance(to :)的布爾返回值。)
您能夠爲新玩家建立Player類的實例,並查看當玩家完成第一級時會發生什麼:
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
// Prints "highest unlocked level is now 2"
複製代碼
若是您建立第二個玩家,嘗試將其移動到遊戲中還沒有被任何玩家解鎖的級別,則設置該玩家當前級別的嘗試將失敗:
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
print("player is now on level 6")
} else {
print("level 6 has not yet been unlocked")
}
// Prints "level 6 has not yet been unlocked"
複製代碼
這一章節內容比較簡單,主要是實例方法和類方法的定義和使用;這裏特別說一下swift裏的類方法定義使用static關鍵詞,還可使用class關鍵詞修飾方法,表示子類的方法能夠覆蓋父類的方法。還有結構體和枚舉裏的方法,默認狀況下是不能夠修改結構體和枚舉裏定義的屬性的,不過可使用mutating關鍵詞修飾方法,達到修改屬性的目的。
最後,有收穫的朋友麻煩動動手指點個贊哦,謝謝~
參考文檔:Swift - Methods