在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 方法 - Methods
方法 - Methods
關(guān)于 Swift
下標腳本(Subscripts)
類和結(jié)構(gòu)體
類型轉(zhuǎn)換(Type Casting)
控制流
析構(gòu)過程(Deinitialization)
集合類型 (Collection Types)
構(gòu)造過程(Initialization)
Optional Chaining
枚舉(Enumerations)
自動引用計數(shù)
繼承(Inheritance)
擴展(Extensions)
泛型
字符串和字符(Strings and Characters)
函數(shù)(Functions)
高級運算符
訪問控制
基本運算符
嵌套類型
閉包(Closures)
協(xié)議
屬性 (Properties)

方法 - Methods

方法是與特定類型相關(guān)聯(lián)的函數(shù)。類、結(jié)構(gòu)體以及枚舉均可以定義實例方法,該方法為指定類型的實例封裝了特定的任務(wù)與功能。類、結(jié)構(gòu)體以及枚舉也能定義類型方法,該方法與類型自身相關(guān)聯(lián)。類型方法類似于在 Objective-C 中的類方法。

在 Swift 中,結(jié)構(gòu)體和枚舉能夠定義方法;事實上這是 Swift 與 C/Objective-C 的主要區(qū)別之一。在 Objective-C 中,類是唯一能定義方法的類型。在 Swift 中,你可以選擇是否定義一個類、結(jié)構(gòu)體或枚舉,且仍可以靈活地對你所創(chuàng)建的類型進行方法的定義。

實例方法

實例方法是某個特定類、結(jié)構(gòu)體或枚舉類型的實例的方法。他們通過提供訪問的方式和修改實例屬性,或提供與實例目的相關(guān)的功能性來支持這些實例的功能性。準確的來講,實例方法的語法與函數(shù)完全一致,參考函數(shù)說明。

實例方法要寫在它所屬的類型的前后括號之間。實例方法能夠訪問他所屬類型的所有的其他實例方法和屬性。實例方法只能被它所屬的類的特定實例調(diào)用。實例方法不能被孤立于現(xiàn)存的實例而被調(diào)用。

下面定義一個簡單的類 Counter 的示例(Counter 可以用來對一個動作發(fā)生的次數(shù)進行計數(shù)):

    class Counter {
        var count = 0
        func increment() {
            count++
        }
        func incrementBy(amount: Int) {
            count += amount
        }
        func reset() {
            count = 0
        }
    }

Counter 可以定義三種實例方法:

  • increment 讓計數(shù)器按一遞增
  • incrementBy(amount: Int) 讓計數(shù)器按一個指定的整數(shù)值遞增
  • reset 將計數(shù)器重置為 0

Counter 這個類還聲明了一個可變屬性 count,用它來保持對當前計數(shù)器值的追蹤。

和調(diào)用屬性一樣,用點語法調(diào)用實例方法:

    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

方法的局部參數(shù)名稱和外部參數(shù)名稱

函數(shù)參數(shù)有一個局部名稱(在函數(shù)體內(nèi)部使用)和一個外部名稱(在調(diào)用函數(shù)時使用),參考外部參數(shù)名稱。對方法參數(shù)也是一樣的,因為方法僅僅是與某一類型相關(guān)的函數(shù)。但是,局部名稱和外部名稱的默認行為不同于函數(shù)和方法。

在 Swift 中的方法和在 Objective-C 中的方法極其相似,像在 Objective-C 一樣,在 Swift 中方法的名稱名稱通常用一個介詞指向方法的第一個參數(shù),比如:with、for 以及 by 等等,前面的 Counter 類的例子中 incrementBy 方法就是這樣的。當其被訪問時,介詞的使用使方法可被解讀為一個句子介詞的使用讓方法在被調(diào)用時能像一個句子一樣被解讀。Swift 這種方法命名約定很容易落實,因為它是用不同的默認處理方法參數(shù)的方式,而不是用函數(shù)參數(shù)(來實現(xiàn)的)。

具體來說,Swift 默認僅給方法的第一個參數(shù)名稱一個局部參數(shù)名稱;但是默認同時給第二個和后續(xù)的參數(shù)名稱局部參數(shù)名稱和外部參數(shù)名稱。這個約定與典型的命名和調(diào)用約定相匹配,這與你在寫 Objective-C 的方法時很相似。這個約定還讓 expressive method 調(diào)用不需要再檢查/限定參數(shù)名。

看看下面這個 Counter 的替換版本(它定義了一個更復(fù)雜的 incrementBy 方法):

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

incrementBy 方法有兩個參數(shù):amountnumberOfTimes。默認地,Swift 僅把 amount 當做一個局部名稱,但是把 numberOfTimes 既看作局部名稱又看做外部名稱。調(diào)用方法如下:

    let counter = Counter()
    counter.incrementBy(5, numberOfTimes: 3)
    // counter value is now 15

你不必對第一個參數(shù)值進行外部參數(shù)名稱的定義,因為從函數(shù)名 incrementBy 已經(jīng)能很清楚地看出它的目的/作用。但是,第二個參數(shù),就要被一個外部參數(shù)名稱所限定,以便在方法被調(diào)用時明確它的作用。

這種默認的行為能夠有效的檢查方法,比如你在參數(shù) numberOfTimes 前寫了個井號(#)時:

    func incrementBy(amount: Int, #numberOfTimes: Int) {
        count += amount * numberOfTimes
    }

這種默認行為使上面代碼意味著:在 Swift 中定義方法使用了與 Objective-C 同樣的語法風(fēng)格,并且方法將以自然表達式的方式被調(diào)用。

修改方法的外部參數(shù)名稱

有時,對一個方法的第一個參數(shù)提供一個外部參數(shù)名是有用的,即使這不是默認行為。你可以自己添加一個明確的外部名稱或你也可以用一個 hash 符號作為第一個參數(shù)的前綴,然后用這個局部名字作為外部名字。

相反,若你不想為方法的第二或后續(xù)參數(shù)提供一個外部名稱,你可以通過使用下劃線 (_) 作為該參數(shù)的顯式外部名稱來覆蓋默認行為。

self 屬性

類型的每一實例都有一個被稱為 self 的隱含屬性,該屬性完全等同于該實例本身。可以在一個實例的實例方法中使用這個隱含的 self 屬性來引用當前實例。

在上面的例子中,increment 方法也可以被寫成這樣:

    func increment() {
        self.count++
    }

實際上,你不必在你的代碼里面經(jīng)常寫 self。不論何時,在一個方法中使用一個已知的屬性或者方法名稱,如果你沒有明確的寫 self,Swift 假定你是指當前實例的屬性或者方法。這種假定在上面的 Counter 中已經(jīng)示范了:Counter 中的三個實例方法中都使用的是 count (而不是 self.count)。

這條規(guī)則的主要例外發(fā)生在當實例方法的某個參數(shù)名稱與實例的某個屬性名稱相同時。在這種情況下,參數(shù)名稱享有優(yōu)先權(quán),并且在引用屬性時必須使用一種更恰當(被限定更嚴格)的方式。你可以使用隱藏的 self 屬性來區(qū)分參數(shù)名稱和屬性名稱。

下面的例子演示 self 消除方法參數(shù)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")
    prints "This point is to the right of the line where x == 1.0"

如果不使用 self 前綴,Swift 就認為兩次使用的 x 都指的是名稱為 x 的函數(shù)參數(shù)。

在實例方法中修改值類型

結(jié)構(gòu)體和枚舉均屬于值類型一般情況下,值類型的屬性不能在其實例方法內(nèi)被修改。

但是,如果在某個具體方法中,你需要對結(jié)構(gòu)體或枚舉的屬性進行修改,你可以選擇變異(mutating)這個方法。方法可以從內(nèi)部變異它的屬性;并且它做的任何改變在方法結(jié)束時都會回寫到原始結(jié)構(gòu)。方法會給它隱含的 self 屬性賦值一個全新的實例,這個新實例在方法結(jié)束后將替換原來的實例。

對于變異方法,將關(guān)鍵字 mutating 放到方法的 func 關(guān)鍵字之前就可以了:

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

上文 Point 結(jié)構(gòu)體定義一個變異(mutating)方法 moveByx,該方法按一定的數(shù)量移動 Point 結(jié)構(gòu)體。moveByX 方法在被調(diào)用時修改了這個 point,而不是返回一個新的 point。方法定義是加上 mutating 關(guān)鍵字,因此,方法可以修改值類型的屬性。

注意:不能在結(jié)構(gòu)體類型常量上調(diào)用變異方法,因為常量的屬性不能被改變,即使想改變的是常量的變量屬性也不行,詳情參見存儲屬性和實例變量

    let fixedPoint = Point(x: 3.0, y: 3.0)
    fixedPoint.moveByX(2.0, y: 3.0)
    // this will report an error

在變異方法中給 self 賦值

變異方法可以賦予隱含屬性 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)
        }
    }

新版的變異方法 moveByX 創(chuàng)建了一個新的分支結(jié)構(gòu)(他的 x 和 y 的值都被設(shè)定為目標值了)。調(diào)用這個版本的方法和調(diào)用上個版本的最終結(jié)果是一樣的。

枚舉的變異方法可以讓 self 從相同的枚舉設(shè)置為不同的成員:

    enum TriStateSwitch {
        case Off, Low, High
        mutating func next() {
            switch self {
            case Off:
                self = Low
            case Low:
                self = High
            case High:
                self = Off
        }
    ovenLight = TriStateSwitch.Low
    ovenLight.next()
    // ovenLight is now equal to .High
    ovenLight.next()
    // ovenLight is now equal to .Off

上述示例中定義了一個三態(tài)開關(guān)的枚舉。每次調(diào)用 next 方法時,開關(guān)在不同的電源狀態(tài)(Off, Low, High)之前循環(huán)切換。

類型方法

如上所述,實例方法是被類型的某個實例調(diào)用的方法。你也可以定義調(diào)用類型本身的方法。這種方法就叫做類型方法。聲明類的類型方法,在方法的 func 關(guān)鍵字之前加上關(guān)鍵字 class;聲明結(jié)構(gòu)體和枚舉的類型方法,在方法的 func 關(guān)鍵字之前加上關(guān)鍵字 static。

注:在 Objective-C 中,你可以定義僅適用于 Objective-C 的類的 type-evel 方法。在 Swift,你可以對所有的類,結(jié)構(gòu)體和枚舉進行 type-evel 方法定義。每種類型方法僅適用于其所支持的類型。

與實例方法相同,也可利用點語法調(diào)用類型方法。但是,你需要在本類型上調(diào)用類型方法,而不是其類型實例上。下面是如何在 SomeClass 類上調(diào)用類型方法的示例:

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

在一個類型方法的方法體內(nèi),self 指向該類型本身,而不是類型的某個實例。對結(jié)構(gòu)體和枚舉來講,這意味著你可以用 self 來消除靜態(tài)屬性和靜態(tài)方法參數(shù)之間的二意性(類似于我們在前面處理實例屬性和實例方法參數(shù)時做的那樣)。

更廣泛地說,你在一個類型方法主體內(nèi)使用的任何未經(jīng)限定的方法和屬性名稱將指的是其他 type-level 方法和屬性。一種類型方法能用其他方法名稱調(diào)用另一種類型方法,而無需在方法名稱前面加上類型名稱的前綴。同樣,結(jié)構(gòu)體和枚舉的類型方法也能夠通過使用不帶有類型名稱前綴的靜態(tài)屬性名稱來訪問靜態(tài)屬性。

下述示例中定義名為 LevelTracker 的結(jié)構(gòu)體,該結(jié)構(gòu)體通過不同級別或階段的游戲?qū)ν婕业倪M度進行監(jiān)測。這是一個單人游戲,但也能在單個設(shè)備上儲存多個玩家的信息。

所有游戲級別(除了級別 1)在游戲初始時都被鎖定。每當玩家完成一個級別,在該設(shè)備上,該級別對所有的玩家解鎖。LevelTracker 結(jié)構(gòu)體用靜態(tài)屬性和方法來監(jiān)測解鎖的游戲級別。也可監(jiān)測每個玩家的當前等級。

    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 結(jié)構(gòu)體監(jiān)測任何玩家已解鎖的最高級別。該值被存儲在成為 highestUnlockedLevel 的靜態(tài)屬性中。

LeveTracker 還定義了兩個類型函數(shù)與 highestUnlockedLevel 配合工作。第一個為 unockLevel 類型函數(shù),一旦新的級別被解鎖,該函數(shù)會更新 highestUnlockedLevel 的值。第二個為 levelIsUnocked 便利型函數(shù),若某個給定級別數(shù)已經(jīng)被解鎖,該函數(shù)則返回 true。(注:沒用使用 LevelTracker.highestUnlockedLevel,這個類型方法還是能夠訪問靜態(tài)屬性 highestUnlockedLevel。)

除了其靜態(tài)屬性和類型方法之外,LeveTracker 還監(jiān)測每個玩家的游戲進程。它使用 currentLevel 實例屬性來監(jiān)測玩家當前進行的級別。

為便于管理 currentLevel 屬性,LeveTracker 定義了實例方法 advanceToLevel。在更新 currentLevel 之前,該方法檢查所要求的新級別是否已經(jīng)解鎖。advanceToLevel 方法返回布爾值以指示是否確實能夠設(shè)置 currentLevel。

下面,Player 類使用 LevelTracker 來監(jiān)測和更新每個玩家的發(fā)展進度:

    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 來監(jiān)測該玩家的游戲進程。它也提供 competedLevel 方法,一旦玩家完成某個指定等級,調(diào)用該方法。該方法為所有玩家解鎖下一個級別并將當前玩家進程更新為下一個級別。(忽略了 advanceToLevel 布爾返回值,因為之前調(diào)用上行時就知道了這個等級已經(jīng)被解鎖了。)

你可以為一個新玩家創(chuàng)建一個 Player 類的實例,然后看這個玩家完成等級一時發(fā)生了什么:

    var player = Player(name: "Argyrios")
    player.completedLevel(1)
    println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
    // prints "highest unlocked level is now 2"

如果你創(chuàng)建了第二個玩家,并嘗試讓他開始一個沒有被任何玩家解鎖的等級,關(guān)于設(shè)置玩家當前等級的嘗試會失?。?

    player = Player(name: "Beto")
    if player.tracker.advanceToLevel(6) {
        println("player is now on level 6")
    } else {
        println("level 6 has not yet been unlocked")
    }
    // prints "level 6 has not yet been unlocked"