天天看點

Swift文法學習之 方法

方法:1.執行個體方法(OC中執行個體方法,通過建立執行個體調用) 2.類型方法(OC中的類方法,類名調用)

類、結構體、枚舉都能夠定義執行個體方法和類型方法;執行個體方法為給定類型的執行個體封裝了詳細的任務與功能。類型方法與類型本身相關聯。

類型方法與 Objective-C 中的類方法(class methods)類似。

結構體和枚舉能夠定義方法是 Swift 與 C/Objective-C 的主要差别之中的一個。

在 Objective-C 中。類是唯一能定義方法的類型。但在 Swift 中。你不僅能選擇是否要定義一個類/結構體/枚舉。還能靈活的在你建立的類型(類/結構體/枚舉)上定義方法。

執行個體方法(Instance Methods)

執行個體方法是屬于某個特定類、結構體或者枚舉類型執行個體的方法。執行個體方法提供訪問和改動執行個體屬性的方法或提供與執行個體目的相關的功能。并以此來支撐執行個體的功能。

執行個體方法要寫在它所屬的類型的前後大括号之間。

執行個體方法能夠隐式訪問它所屬類型的全部的其它執行個體方法和屬性。執行個體方法僅僅能被它所屬的類的某個特定執行個體調用。執行個體方法不能脫離于現存的執行個體而被調用。

// 執行個體方法的建立

class Counter {

// 可變屬性

var count = 0

// 三個執行個體方法

func increment() {

count++

}

func incrementBy(amount: Int) {

count += amount

func reset() {

count = 0

}

// 執行個體方法的調用 通過建立執行個體打點調用

let counter = Counter()

counter.increment()

counter.incrementBy(5)

counter.reset()

方法的局部參數名稱和外部參數名稱(Local and External Parameter Names for Methods)

方法參數與函數參數一樣(由于方法就是函數。僅僅是這個函數與某個類型相關聯了,能夠同一時候有一個局部名稱(在函數體内部使用)和一個外部名稱(在調用函數時使用).)。可是。方法和函數的局部名稱和外部名稱的預設行為是不一樣的。

Swift 中的方法和 Objective-C 中的方法極其類似。像在 Objective-C 中一樣,Swift 中方法的名稱通經常使用一個介詞指向方法的第一個參數。比方:with。for,by等等。前面的Counter類的樣例中incrementBy方法就是這樣的。介詞的使用讓方法在被調用時能像一個句子一樣被解讀。

和函數參數不同。對于方法的參數,Swift 使用不同的預設處理方式。這能夠讓方法命名規範更easy寫。

詳細來說,Swift 預設僅給方法的第一個參數名稱一個局部參數名稱;預設同一時候給第二個和興許的參數名稱局部參數名稱和外部參數名稱。

這個約定與典型的命名和調用約定相适應。 與你在寫 Objective-C 的方法時非常類似。這個約定還讓表達式方法在調用時不須要再限定參數名稱。

看看以下這個Counter的還有一個版本号(它定義了一個更複雜的incrementBy方法):

var count: Int = 0

func incrementBy(amount: Int, numberOfTimes: Int) {

count += amount * numberOfTimes

incrementBy方法有兩個參數: amount和numberOfTimes。

預設情況下,Swift 僅僅把amount當作一個局部名稱,可是把numberOfTimes即看作局部名稱又看作外部名稱。以下調用這種方法:

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 相同的文法風格,而且方法将以自然表達式的方式被調用。

改動方法的外部參數名稱(Modifying External Parameter Name Behavior for Methods)

有時為方法的第一個參數提供一個外部參數名稱是非常實用的,雖然這不是預設的行為。

你能夠自己加入一個顯式的外部名稱或者用一個井号(#)作為第一個參數的字首來把這個局部名稱當作外部名稱使用。

相反,假設你不想為方法的第二個及興許的參數提供一個外部名稱,能夠通過使用下劃線(_)作為該參數的顯式外部名稱,這樣做将覆寫預設行為。

func incrementBy(amount: Int, numberOfTimes: Int,:Int,:String) {

count += amount * numberOfTimes

}

self屬性(The self Property)

類型的每一個執行個體都有一個隐含屬性叫做self,self全然等同于該執行個體本身。

你能夠在一個執行個體的執行個體方法中使用這個隐含的self屬性來引用目前執行個體。

上面樣例中的increment方法還能夠這樣寫:

func increment() {

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的函數參數。

在執行個體方法中改動值類型(Modifying Value Types from Within Instance Methods)

結構體和枚舉是值類型。普通情況下。值類型的屬性不能在它的執行個體方法中被改動。

須要在某個詳細的方法中改動結構體或者枚舉的屬性,你能夠選擇變異(mutating)這種方法,然後方法就能夠從方法内部改變它的屬性。而且它做的不論什麼改變在方法結束時還會保留在原始結構中。

方法還能夠給它隐含的self屬性指派一個全新的執行個體,這個新執行個體在方法結束後将替換原來的執行個體。

要使用變異方法, 将keywordmutating 放到方法的funckeyword之前就能夠了:

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)”

上面的Point結構體定義了一個變異方法(mutating method)moveByX。moveByX用來移動點。

moveByX方法在被調用時改動了這個點,而不是傳回一個新的點。方法定義時加上mutatingkeyword,這才讓方法能夠改動值類型的屬性。

注意:不能在結構體類型常量上調用變異方法,由于常量的屬性不能被改變。即使想改變的是常量的變量屬性也不行

let fixedPoint = Point(x: 3.0, y: 3.0)

fixedPoint.moveByX(2.0, y: 3.0)

// this will report an error

在變異方法中給self指派(Assigning to self Within a Mutating Method)

變異方法能夠賦給隐含屬性self一個全新的執行個體。上面Point的樣例能夠用以下的方式改寫:

mutating func moveByX(deltaX: Double, y deltaY: Double) {

self = Point(x: x + deltaX, y: y + deltaY)

新版的變異方法moveByX建立了一個新的結構(它的 x 和 y 的值都被設定為目标值)。

調用這個版本号的方法和調用上個版本号的終于結果是一樣的。

枚舉的變異方法能夠把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 如今等于 .Off

上面的樣例中定義了一個三态開關的枚舉。每次調用next方法時,開關在不同的電源狀态(Off,Low。High)之前循環切換。

類型方法(Type Methods)

執行個體方法是被類型的某個執行個體調用的方法。你也能夠定義類型本身調用的方法。這樣的方法就叫做類型方法。

聲明類的類型方法,在方法的funckeyword之前加上keywordclass;

聲明結構體和枚舉的類型方法。在方法的funckeyword之前加上keywordstatic。

注意:在 Objective-C 裡面。你僅僅能為 Objective-C 的類定義類型方法(type-level methods)。在 Swift 中。你能夠為全部的類、結構體和枚舉定義類型方法:每一個類型方法都被它所支援的類型顯式包括。

類型方法和執行個體方法一樣用點文法調用。

可是。你是在類型層面上調用這種方法。而不是在執行個體層面上調用。以下是怎樣在SomeClass類上調用類型方法的樣例:

class SomeClass {

class func someTypeMethod() {

// type method implementation goes here

SomeClass.someTypeMethod()

在類型方法的方法體(body)中。self指向這個類型本身。而不是類型的某個執行個體。

對于結構體和枚舉來說,這意味着你能夠用self來消除靜态屬性和靜态方法參數之間的歧義(類似于我們在前面處理執行個體屬性和執行個體方法參數時做的那樣)。

一般來說。不論什麼未限定的方法和屬性名稱,将會來自于本類中另外的類型級别的方法和屬性。一個類型方法能夠調用本類中還有一個類型方法的名稱。而無需在 方法名稱前面加上類型名稱的字首。相同,結構體和枚舉的類型方法也能夠直接通過靜态屬性的名稱訪問靜态屬性,而不須要類型名稱字首。

遊戲初始時,全部的遊戲等級(除了等級 1)都被鎖定。

每次有玩家完畢一個等級,這個等級就對這個裝置上的全部玩家解鎖。

LevelTracker結構體用靜态屬性和方法監測遊戲的哪個等級已經被解鎖。它還監測每一個玩家的目前等級。

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

LevelTracker監測玩家的已解鎖的最高等級。

這個值被存儲在靜态屬性highestUnlockedLevel中。

LevelTracker還定義了兩個類型方法與highestUnlockedLevel配合工作。第一個類型方法是unlockLevel:一旦新等級被解鎖,它會更新highestUnlockedLevel的值。第二個類型方法是levelIsUnlocked:假設某個給定的等級已經被解鎖。它将傳回true。(注意:雖然我們沒有使用類似LevelTracker.highestUnlockedLevel的寫法,這個類型方法還是能夠訪問靜态屬性highestUnlockedLevel)

除了靜态屬性和類型方法,LevelTracker還監測每一個玩家的進度。它用執行個體屬性currentLevel來監測玩家目前的等級。

為了便于管理currentLevel屬性,LevelTracker定義了執行個體方法advanceToLevel。這種方法會在更新currentLevel之前檢查所請求的新等級是否已經解鎖。

advanceToLevel方法傳回布爾值以訓示能否夠設定currentLevel。

以下。Player類使用LevelTracker來監測和更新每一個玩家的發展進度:

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

Player類建立一個新的LevelTracker執行個體來監測這個使用者的發展進度。

它提供了completedLevel方法:一旦玩家完畢某個指定等級就調用它。這種方法為全部玩家解鎖下一等級,而且将目前玩家的進度更新為下一等級。

(我們忽略了advanceToLevel傳回的布爾值,由于之前調用LevelTracker.unlockLevel時就知道了這個等級已經被解鎖了)。

你還能夠為一個新的玩家建立一個Player的執行個體,然後看這個玩家完畢等級一時發生了什麼: