美文网首页
Swift5.1学习随笔之属性

Swift5.1学习随笔之属性

作者: SAW_ | 来源:发表于2020-04-23 15:31 被阅读0次

    swift中跟实例相关的属性可以分为2大类

    1、存储属性(Stored Property)
    2、计算属性(Computed Property)

    struct Circle {
        //存储属性
        var radius: Double
        //计算属性
        var diameter: Double {
            set {
                radius = newValue / 2
            }
            get {
                radius * 2
            }
        }
    }
    

    存储属性(Stored Property)

    • 类似于成员变量的概念
    • 存储在实例的内存中
    struct Point {
        var x: Int
        var y: Int
    }
    var p = Point(x: 10, y: 20)
    print(MemoryLayout.stride(ofValue: p)) //16
    //占用16个字节,其中8个用于x,8个用于y
    
    • 结构体、类可以定义存储属性
    • 枚举不可以定义存储属性
    enum Season {
        case spring, summer
    }
    var s = Season.spring
    print(MemoryLayout.stride(ofValue: s)) // 1
    //枚举变量只需要1个字节就可以知道区分知道存储的是哪一个case
    
    //枚举可以设置关联类型
    enum Season2 {
        case spring(Int), summer(Double)
    }
    var s2 = Season2.spring(10)
    print(MemoryLayout.stride(ofValue: s2)) // 16
    //关联的Int类型也是存储在枚举变量内,占用8个字节
    
    //原始值
    enum Season3: Int {
        case spring = 2, summer = 5
    }
    var s3 = Season3.spring
    print(MemoryLayout.stride(ofValue: s3)) // 1
    //枚举变量依然只需要1个字节就可以知道区分知道存储的是哪一个case
    
    //所以枚举类型内存中要么存储case用来区分,要么用来存储关联类型,
    

    关于存储属性,Swift有个明确的规定
    在创建类或者结构体实例的时候,必须为所有的存储属性设置一个合适的初始值

    • 可以在初始化器里面为存储属性设置一个初始值
    struct Point {
        var x: Int
        var y: Int
        init() {
            x = 10
            y = 10
        }
    }
    
    • 可以分配一个默认的属性值作为属性定义的一部分
    struct Point {
        var x: Int = 11
        var y: Int = 12
    }
    

    计算属性(Computed Property)

    • 本质就是方法(函数)
    • 不占用实例的内存
    • 枚举、结构体、类都可以定义计算属性
    struct Circle {
        //存储属性
        var radius: Double
        //计算属性
        var diameter: Double {
            set {
                radius = newValue / 2
            }
            get {
                radius * 2
            }
        }
    }
    var c = Circle(radius: 10)
    print(MemoryLayout.stride(ofValue: c)) // 8
    

    一个结构体变量c占用8个字节,一个Double也占用8个字节,所以说明了计算属性diameter不占用结构体变量c的内存,它本质是一个方法实现,不存在diameter这个成员变量。

    var c = Circle(radius: 10)
    print(c.radius) // 10.0
    print(c.diameter) // 调用diameter的get方法,计算 radius * 2 = 20.0
    c.radius = 15
    print(c.diameter) // 调用diameter的get方法,计算 radius * 2 = 30.0
    c.diameter = 60 // 调用diameter的set方法,会导致radius重新计算 radius = newValue / 2
    print(c.radius) // 30.0
    
    一些注意点

    1、set传入的新值默认叫做newValue,也可以自定义

    struct Circle {
        var radius: Double
        var diameter: Double {
            set(newDiameter) {
                radius = newDiameter / 2
            }
            get {
                radius * 2
            }
        }
    }
    

    2、只读计算属性:只有get,没有set

    struct Point {
        var x: Int
        var y: Int {
            get {
                10
            }
        }
    }
    var p = Point(x: 10)
    p.y = 20 //报错:Cannot assign to property: 'y' is a get-only property
    
    //只有get,可以省略写法
    struct Point {
        var x: Int
        var y: Int { 10 }
    }
    

    3、计算属性只能用var,不能用let,即使它是只读计算属性

    struct Point {
        var x: Int
        let y: Int { 10 } //报错:'let' declarations cannot be computed properties
    }
    

    4、枚举rawValue原始值的本质就是一个只读的计算属性

    enum Season: Int {
        case spring = 1, summer, autum, winter
        var rawValue: Int {
            switch self {
            case .spring:
                return 11
            case .summer:
                return 12
            case .autum:
                return 13
            case .winter:
                return 14
            }
        }
    }
    var s = Season.spring
    print(s.rawValue) // 1
    s.rawValue = 20 //报错:Cannot assign to property: 'rawValue' is a get-only property
    

    5、通过private(set)设置属性为readonly,在当前文件内可以修改,外部引用只能读取

    private(set) var name: String
    

    延迟存储属性(Stored Property)

    使用lazy可以定义一个延迟存储属性,在第一次用到属性的时候才会进行初始化,类似懒加载
    1、延迟存储属性必须用var
    2、当结构体包含一个延迟存储属性时候,只有var才能访问延迟存储属性,因为延迟属性初始化时候需要改变结构体的内存

    属性观察器(Property Observer)

    1、可以为非lazyvar存储属性设置属性观察器(类似KVO)

    • willSet会传递新值,默认叫newValue
    • didSet会传递旧值,默认叫oldValue
    • 在初始化器中设置属性值不会触发willSetdidSet
    struct Circle {
        var radius: Double {
            willSet {
                print("willSet", newValue)
            }
            didSet {
                print("didSet", oldValue, radius)
            }
        }
        init() {
            self.radius = 1.0
            print("Circle init")
        }
    }
    
    //Circle init
    var circle = Circle()
    
    //willSet 10.5
    //didSet 1.0 10.5
    circle.radius = 10.5
    
    //10.5
    print(circle.radius)
    

    全局变量、局部变量

    属性观察器、计算属性的功能,同样可以应用在全局变量、局部变量上

    var num: Int {
        get {
            return 10
        }
        set {
            print("setNum", newValue)
        }
    }
    num = 11 // setNum 11
    print(num) // 10
    
    func test() {
        var age: Int = 10 {
            willSet {
                print("willSet", newValue)
            }
            didSet {
                print("didSet", oldValue, age)
            }
        }
        age = 11
        // willSet 11
        // didSet 10 11
    }
    test()
    

    类型属性(Type Property)

    严格来讲,属性可以分为:

    1、实例属性(Instance Property):只能通过实例去访问
    * 存储实例属性(Stored Instance Property):存储在实例的内存中,每个实例都有1份
    * 计算实例属性(Computed Instance Property)

    2、类型属性(Type Property):只能通过类型去访问
    * 存储类型属性(Stored Type Property):整个程序运行中,就只有1份内存(类似于全局变量)

    相关文章

      网友评论

          本文标题:Swift5.1学习随笔之属性

          本文链接:https://www.haomeiwen.com/subject/uxhaihtx.html