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
            }
        }
        
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章