swift簡單總結(二十一)—— 方法

版本記錄

版本號 時間
V1.0 2017.07.29

前言

我是swift2.0的時候開始接觸的,記得那時候還不是很穩定,公司的項目也都是用oc做的,并不對swift很重視,我自己學了一段時間,到現在swift3.0+已經出來了,自己平時也不寫,忘記的也差不多了,正好項目這段時間已經上線了,不是很忙,我就可以每天總結一點了,希望對自己對大家有所幫助。在總結的時候我會對比oc進行說明,有代碼的我會給出相關比對代碼。
1. swift簡單總結(一)—— 數據簡單值和類型轉換
2. swift簡單總結(二)—— 簡單值和控制流
3. swift簡單總結(三)—— 循環控制和函數
4. swift簡單總結(四)—— 函數和類
5. swift簡單總結(五)—— 枚舉和結構體
6. swift簡單總結(六)—— 協議擴展與泛型
7. swift簡單總結(七)—— 數據類型
8. swift簡單總結(八)—— 別名、布爾值與元組
9. swift簡單總結(九)—— 可選值和斷言
10. swift簡單總結(十)—— 運算符
11. swift簡單總結(十一)—— 字符串和字符
12. swift簡單總結(十二)—— 集合類型之數組
13. swift簡單總結(十三)—— 集合類型之字典
14. swift簡單總結(十四)—— 控制流
15. swift簡單總結(十五)—— 控制轉移語句
16. swift簡單總結(十六)—— 函數
17. swift簡單總結(十七)—— 閉包(Closures)
18. swift簡單總結(十八)—— 枚舉
19. swift簡單總結(十九)—— 類和結構體
20. swift簡單總結(二十)—— 屬性

方法

??大家還記得OC中的方法吧,包括對象方法和類方法。在swift中同樣有方法,方法是某些特定類型相關聯的函數。類、結構體和枚舉都可以定義實例方法,實例方法為給定類型的實例封裝了具體的任務和功能。類、結構體和枚舉也可以定義類型方法,類型方法與類型相關聯,與OC中的類方法相似。

??結構體和枚舉能定義方法是swiftOC的主要區別,在OC中,類是唯一能夠定義方法的類型,但是在swift中,你可以選擇是否定義一個類、結構體還是枚舉,還能靈活的在你定義的類、結構體、枚舉中定義方法。

本篇文章主要從下面進行講述:

  • 實例方法(Instance Methods)
  • self 屬性
  • 類型方法(Type Methods)

實例方法

??實例方法屬于某一個特定的類、結構體或者枚舉類型實例方法,實例方法提供訪問和修改實例屬性的方法或提供與實例目的相關的功能,并以此支撐實例的功能,實例方法的語法與函數完全一致。

??實例方法要寫在它所屬的類型前后大括號之間,實例方法能夠隱式訪問它所屬類型的所有其他實例方法和屬性,實例方法只能被它所屬的類的某個特定實例調用,實例方法不能脫離于現存的實例而被調用。

下面看一個例子。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let counter = Counter()
        counter.increment()
        counter.incrementBy(step: 10)
        counter.rest()
    }
}

class Counter {
    var count = 0
    func increment() {
        count += 1
        print(count)
    }
    
    func incrementBy(step : Int) {
        count += step
        print(count)
    }
    
    func  rest() {
        count = 0
        print(count)
    }
}

下面看輸出結果

1
11
0

這里類Counter定義了三個方法func increment()func incrementBy(step : Int)func rest()

1. 方法的局部參數名稱和外部參數名稱 - Local and External Parameter Names for Methods

??講解函數的時候,我們知道函數可以同時有一個局部名稱(在函數體內部使用)和一個外部名稱(在調用函數時使用)。方法參數也是一樣的,但是方法和函數的局部名稱和外部名稱的默認行為是不一樣的。

??方法參數列表與OC很類似,你不必定義成外部參數,swift會默認方法的參數為外部參數,下面看一下例子。

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        
        let counter = Counter()
        counter.incrementBy(amount: 10, numberOfTimes: 5)
    }
}

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

下面看輸出結果

50

這里,大家注意下:

counter.incrementBy(amount: 10, numberOfTimes: 5)

調用的時候都默認兩個參數都有外部參數了。


self 屬性

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

上面的例子可以改寫為:

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

可見,增加了self也是可以的。

self.count += amount * numberOfTimes

這里,self不是必須的,swift假定你是指當前實例的屬性或者方法。但是有的時候self有它好用的地方。

struct Point {
    var x = 0.0
    var y = 0.0
    func isToTheRightOfX(x : Double) -> Bool {
        print(self.x)
        print(x)
        return self.x > x
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.lightGray
        let somePoint = Point(x: 4.0, y: 5.0)
        if somePoint.isToTheRightOfX(x: 1.0) {
            print("This point is to the right of the line where x == 1.0")
        }
    }
}

下面看輸出結果

4.0
1.0
This point is to the right of the line where x == 1.0

??這種情況使用self就有用了,如果不使用selfswift就認為兩次使用的x都是指的是名稱為x的函數參數。但是這個情況完全可以避免,我們可以定義函數參數的時候不與結構體成員變量重復,容易引起歧義,代碼的可讀性也會差很多。

1. 在實例方法中修改值類型 - Modifying Values Types from Within Instance Methods

??結構體和枚舉都是值類型,值類型的屬性不能再它的實例方法中修改。但是,如果你確實需要在某個具體方法中修改結構體或者枚舉的屬性,你可以選擇使用變異mutating這個方法,然后方法就可以從方法內部改變它的屬性,并且它做的任何改變在方法結束時還保留在原始結構中。方法還可以給它隱含self屬性賦值一個全新的實例,這個新實例在方法結束后將替換原來的實例。

下面看代碼。

struct Point {
    var x = 0.0
    var y = 0.0
    mutating func movePoint(deltaX : Double, deltaY : Double) {
        x += deltaX
        y += deltaY
        print("(\(x),\(y))")
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var somePoint = Point(x : 1.0, y : 2.0)
        somePoint.movePoint(deltaX: 5.0, deltaY: 5.0)
    }
}

下面看輸出結果

(6.0,7.0)

還有一點,下面的必須定義為變量var,才可以修改。

var somePoint = Point(x : 1.0, y : 2.0)

如果修改成let就會報錯,即使想改變常量的變量屬性也不可以。

2. 在變異方法中給self賦值 - Assigning to self within a Mutating Method

變異方法能夠給隱含屬性self一個全新的實例,下面看代碼。

struct Point {
    var x = 0.0
    var y = 0.0
    mutating func movePoint(deltaX : Double, 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
        }
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var light = TriStateSwitch.Low
        print(light)
        
        light.next()
        print(light)
        
        light.next()
        print(light)
    }
}

下面看一下輸出結果

Low
High
Off

類型方法

??它相當于OC中的類方法,在swift中叫做類型方法。聲明類的類型方法是要在func關鍵字之前加上關鍵字class,聲明結構體和枚舉的類型方法,在方法的func關鍵字之前加上關鍵字static。也即是說你可以在swift中不僅為類定義類型方法,還可以為結構體和枚舉定義類型方法。

類型方法都是按照如下方式進行調用。

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

someClass.someTypeMethod()

??一個類型方法可以調用本類中另外一個類型方法的名稱,而無需在方法名稱前面加上類型名稱的前綴,同樣結構體和枚舉的類型方法也能夠直接通過靜態屬性的名稱訪問靜態屬性,而不需要類型名稱前綴。

struct LevelTracker {
    static var highestUnlockLevel = 1
    static func unlockLevel(level : Int){
        if level > highestUnlockLevel {
            highestUnlockLevel = level
        }
    }
    
    static func levelIsUnlocked(level : Int) -> Bool{
        return level <= highestUnlockLevel
    }
    
    var currentLevel = 1
    mutating func advanceToLevel(level : Int) -> Bool {
        if LevelTracker.levelIsUnlocked(level: level){
            currentLevel = level
            return true
        }
        else {
            return false
        }
    }
}

LevelTracker監測玩家已解鎖的最高等級,這個值被存儲在靜態屬性highestUnlockLevel中,LevelTracker還定義了兩個類型方法unlockLevellevelIsUnlocked,方法unlockLevel:一旦新等級被解鎖,就會更新highestUnlockLevel的值,方法levelIsUnlocked:如果某個給定的等級已經解鎖就會返回true。同時,currentLevel用于監測玩家當前等級,定義了advanceToLevel實例方法進行管理,這個方法會在更新currentLevel之前判斷請求的等級是否已經解鎖,返回的是一個Bool值。

下面我們看玩家類使用LevelTracker監測和更新每一個玩家的發展進度。

class Player {
    var tracker = LevelTracker()
    let playerName : String
    
    func completedLevel(level : Int) {
        LevelTracker.unlockLevel(level: level + 1)
        tracker.advanceToLevel(level: level + 1)
    }
    
    init(name: String) {
        playerName = name
    }
}

Player類創建了一個LevelTracker實例tracker來監測這個用戶的等級進度,提供了方法completedLevel:一旦玩家完成某個指定等級就調用它,這個方法為所有玩家解鎖下一級,并更新當前進度為下一等級。

下面我們看全部完整代碼。

struct LevelTracker {
    static var highestUnlockLevel = 1
    static func unlockLevel(level : Int){
        if level > highestUnlockLevel {
            highestUnlockLevel = level
        }
    }
    
    static func levelIsUnlocked(level : Int) -> Bool{
        return level <= highestUnlockLevel
    }
    
    var currentLevel = 1
    mutating func advanceToLevel(level : Int) -> Bool {
        if LevelTracker.levelIsUnlocked(level: level){
            currentLevel = level
            return true
        }
        else {
            return false
        }
    }
}

class JJSwiftVC: UIViewController
{
    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        var player = Player(name : "John")
        player.completedLevel(level: 1)
        print("highest level is unlocked is \(LevelTracker.highestUnlockLevel)")
    }
}

class Player {
    var tracker = LevelTracker()
    let playerName : String
    
    func completedLevel(level : Int) {
        LevelTracker.unlockLevel(level: level + 1)
        tracker.advanceToLevel(level: level + 1)
    }
    
    init(name: String) {
        playerName = name
    }
}

下面看輸出結果

highest level is unlocked is 2

現在可以看見未解鎖的等級到了2了。

后記

未完,待續~~~

風景
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容