Swift中的方法、下標與繼承

方法

  • 特點
  1. 枚舉、結構體、類都可以定義實例方法、類型方法
  2. 實例方法:通過實例調用
  3. 類型方法:通過類型調用,用static 或者 class關鍵字修飾定義
  • self關鍵字
  1. 在實例方法中代表實例
  2. 在類型方法中代表類型
    class MethodUseDemo {
        enum Direction {
            case top, left, bottom, right
            
            func printInstanceInfo() {
                print("這是一個定義在枚舉類型中的實例方法")
            }
            
            static func printCurInfo() {
                print("這是一個枚舉中的類型方法")
            }
        }
        
        struct UserInfo {
            var name: String = ""
        }
        
    }

  • mutating 關鍵字的使用
    1. 默認情況下,結構體、枚舉是值類型,值類型的屬性不能被自身的實例方法修改
    2. func前面添加mutating可以允許修改行爲
    struct PointMutating {
        var x = 0.0, y = 19.0
        mutating func moveToPoint(x: Double, y: Double) {
            self.x = x
            self.y = y
        }
    }
    
    //涉及到要改變direction的值,這裏需要添加關鍵字mutating關鍵字
    enum DirectionStruct {
        case left, bottom, right, top
        mutating func next() {
            switch self {
            case .left: self = .bottom
            case .bottom: self = .right
            case .right: self = .top
            case .top: self = .left
            }
        }
    }
  • 使用@discardableResult 消除函數調用後返回值未被使用的警告
    @discardableResult
    func get() -> Int {
        return 10
    }

下標(subscript)

  • 特點
    1. 使用subscript 可以給任意的類型(枚舉、結構體、類)增加下標功能,也叫下標腳本
    2. subscript的語法類似於實例方法、計算屬性,本質就是方法(函數)
    3. subscript中定義的返回值類型決定了get方法中的返回類型,以及set方法中的newvalue的類型
    4. subscript可以接收多個參數,並且類型任意
    5. subscript可以沒有set方法,但必須要有get方法
    6. 如果只有get方法,可以省略get
    7. 可以設置參數標籤
    8. 下標可以是類型方法
    9. 可以設置多個參數的下標
class PointSubscript {
        
        var x = 0.0, y = 0.0, z = 10.0
        subscript(index: Int) -> Double{
            
            set {
                if index == 0{
                    x = newValue
                }else if index == 1{
                    y = newValue
                }
            }
            
            get {
                if index == 0 {
                    return x
                }else if index == 1 {
                    return y
                }
                return 0
            }
        }
        
        subscript(index: Double, second: Double, three: Double) -> (Double, Double, Double){
            set {
                x = index
                y = second
                z = three
            }
            
            get {
                return (x, y, z)
            }
        }
        //只有get方法,可以省略get關鍵字
        subscript(num: Double) -> Double{
            x + y + z
        }
        
        //設置參數標籤
        subscript(in x: Double, in y: Double,in z: Double) -> Double{
            x + y + z
        }
        
        //下標可以是類型方法
        class subscript(x: Double, y: Double, z: Double) -> Double{
            x + y + z
        }
        
    }

// 多個參數的下標
class MutiScriptUseClass {
        
        static let shareInstance = MutiScriptUseClass()
        var data = [[0, 1, 2],
                    [0, 1, 2],
                    [0, 1, 2]]
        
        subscript(row: Int, col: Int) -> Int{
            set{
                data[row][col] = newValue
            }
            get{data[row][col]}
        }
        
    }
  • 結構體下標與類下標的一點區別

    1. 結構體下標修改成員變量需要重新創建一份新的結構體然後將新值賦值給變量
    2. 類下標可以直接進行set設置

    根本原因在於:
    結構體因爲是值類型,存儲在棧空間,所以通過get取值的時候會copy一份臨時變量,直接修改x實際上是修改臨時變量的值,原始並沒有被修改,所以需要通過set方法去設置對應的新的數值。而class因爲是通過棧中存儲的指針來引用實例,所以通過get拿到的是堆空間的實例對象的地址,所以通過地址去修改x或者y的成員變量時可以直接修改的。

struct PointDemo {
        var x = 10, y = 10
    }
    
    //使用類可以直接修改x,y的值,不用再在棧空間申請一塊臨時的控件存儲PointDemo結構體內容了
    class PointClassDemo {
        var x = 10, y = 20
    }
    
    class PointDemoManager {
        
        var point = PointDemo()
        var pointStruct = PointClassDemo()
        
        subscript(index: Int) -> PointDemo {
            set {
                point = newValue
            }
            get{
                point
            }
        }
        
        
        subscript(at index: Int) -> PointClassDemo {
            get {
                pointStruct
            }
        }
        
    }
    
    func testPointDemo() {
        let manager = PointDemoManager()
        manager[0].x  = 11  //等同於 manager[0] = PointDemo(x: 11, y: manager[0].y)
        manager[0].y = 12  //等同於 manager[0] = PointDemo(x: manager[0].x, y: 12)
        
//        manager[at 0].x =11
    }

繼承

  • 特點
  1. 值類型(枚舉、結構體)不支持繼承,只有類支持繼承
  2. Swift 不像OC、Java的規定:任何類最終都要繼承自某個基類,Swift可以不用繼承任何基類而單獨定義類型
  3. 子類可以重寫父類的下標、方法、屬性,重寫必須加上override關鍵字
  4. 類會默認分配16個字節的存儲空間來存放對象的 引用計數和類的信息
  • 繼承重寫父類相關的信息

    1. 重寫實例方法、下標
    2. 重寫類型方法、下標
  • 繼承重寫規則

    1. class修飾的類型方法、下標,允許被子類重寫
    2. static修飾的類型方法、下標,不允許被子類重寫

注意:如果此時繼承父類重寫父類方法之後,如果重寫的方法不想繼續被子類去重寫,那麼可以此時在重寫的方法前面添加static關鍵字修飾來確保子類不能夠重寫當前的方法.

class AnimalSubscript {
        func speak() {
            print("animal speak")
        }
        subscript(index: Int) -> Int {index}
        
        class func eat() {
            print("animal eat")
        }
        
        static func drink() {
            print("animal drink")
        }
    }
    
    class Cat: AnimalSubscript {
        override func speak() {
            print("cat speak")
        }
        
        override subscript(index: Int) -> Int {index + 20}
        override class func eat() {
            print("cat eat")
        }
        
        //此時重寫的方法將不能被子類重寫修改
//        override static func eat(){
//            print("終結當前的方法")
//        }
        
    }
  • 重寫屬性需要注意的點
    1. 子類可以將父類的計算屬性、存儲屬性重寫爲計算屬性
    2. 子類不可以將父類重寫爲存儲屬性
    3. 只能重寫var變量屬性。不能重寫let屬性
    4. 重寫時,屬性名、類型要一致
    5. 子類重寫後的屬性權限不能小於父類屬性的權限
    6. 如果父類屬性是隻讀的,那麼子類重寫後的屬性可以是只讀的,也可以是可讀寫
    7. 如果父類屬性是可讀可寫的,那麼子類重寫後的屬性也必須是可讀寫
class OverrideCircle {
        //懶加載
        lazy var lazyVar: Int = {
            return 1
        }()
        
        private(set) var onlyRead: Int = 0
        var radius: Int = 0
        var diameter: Int{
            get {
                print("get diameter")
                return (radius * 2)
            }
            
            set {
                radius = newValue
                print("Circle set diameter")
            }
        }
        
    }
    
    class OverrideCircleSon: OverrideCircle {
        
        var newRadius = 0
        override var diameter: Int {
            get {
                print("overrideCircleSon get value")
                return radius * 2
            }
            
            set {
                print("overrideCircleSon set value")
                radius = newValue
            }
        }
        
        override var radius: Int{
            get {
                print("reWrite stored perproty of radius")
                return newRadius
            }
            
            set {
                print("reGet sotre perproty of radius")
                newRadius = newValue
            }
        }
    }
  • 屬性觀察器

    1. 可以在子類爲父類屬性(除了只讀計算屬性、let屬性)增加屬性觀察器
    2. setwillsetgetwillget均不能共存的
    3. 不管父類是實例屬性,類型屬性或者存儲屬性、計算屬性·,子類都可以爲父類添加觀察屬性`
class perprotyObserverClass: OverrideCircle{
        override var radius: Int{
            willSet {
                print("will set value", newValue)
            }
            didSet {
                //此時的radius不會引發死循環,因爲此時並沒有重寫計算屬性,此時訪問的仍舊是radius本身,
                //屬性監聽器的實現是通過中間臨時變量來實現的,所以不存在死循環
                print("set value finish", oldValue, radius)
            }
        }
        //不能夠正常添加觀察期監聽
//        override var onlyRead: Int{
//            willSet {
//
//            }
//        }
        override var lazyVar: Int{
            willSet {
                print("lazy load will set")
            }
        }
    }
  • final 使用
    1. final修飾的方法、下標、屬性,禁止被重寫
    2. final修飾的類,禁止被繼承
    final class finalClass {
        final var radius: Int {
            set {
                print("radius write")
            }
            get {
                print("circle get radius")
                return 20
            }
        }
        
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章