JHHK

欢迎来到我的个人网站
行者常至 为者常成

8_1、属性(一)

目录

实例说明

func instanceExplain(){
        
    //枚举
    enum Season{
        case spring,summer,autumn,winter
    }
    let s = Season.spring
    
    
    //结构体
    struct Point{
        var x:Int = 0
        var y:Int = 0
    }
    let p = Point()
    
    
    //类
    class Size{
        var width = 0
        var height = 0
    }
    let si = Size()
    
    // s p si就是实例
    print(s,p,si,separator:"\n")
}

存储属性

func storedPropertyExplain(){
    
    /**
    Swift中跟实例相关的属性可以分为2大类:存储属性、计算属性
     
    存储属性(Stored Property)
        类似于成员变量这个概念
        存储在实例的内存中
        结构体、类可以定义存储属性
        枚举不可以定义存储属性
     
    关于存储属性,Swift有个明确的规定
        在创建类 或 结构体的实例时,必须为所有的存储属性设置一个合适的初始值
        可以在初始化器里为存储属性设置一个初始值
        可以分配一个默认的属性值作为属性定义的一部分
     */

    
    //1、结构体的存储属性
    do{
        struct Point{
            var x:Int = 0//存储属性 类似于成员变量 存储在实例的内存中
            var y:Int = 0//存储属性 类似于成员变量 存储在实例的内存中
        }
        var p = Point()
        p.x = 10
        p.y = 10
        print(p)//Point(x: 10, y: 10)
    }
    
    
    
    //2、类的存储属性
    do{
        class Size{
            var width:Int = 0//存储属性 类似于成员变量 存储在实例的内存中
            var height:Int = 0//存储属性 类似于成员变量 存储在实例的内存中
        }
        let s = Size()
        s.width = 80
        s.height = 180
        print(s.width,s.height)//80 180
    }

    
    
    //3、枚举没有存储属性
    do{
        //实例占用1个字节 侧面证明没有存储属性 内存中没有放置存储属性的空间
        enum Season{
            //var stored:Int//报错 Enums must not contain stored properties
            case spring,summer,autumn,winner
        }
        
        //实例占用16个字节 侧面证明没有存储属性 内存中没有放置存储属性的空间
        enum Date{
            //var stored:Int////报错 Enums must not contain stored properties
            case day(Int)
            case month(Int)
            case year(Int)
        }
        
        print("DateSize = ",MemoryLayout<Date>.size);//9
        print("DateStride = ",MemoryLayout<Date>.stride);//16
        print("DateAlignment = ",MemoryLayout<Date>.alignment);//8
    }
}

计算属性

func computedPropertyExplain(){
    
    /**
     计算属性(Computed Property)
         本质就是方法(函数)
         不占用实例的内存
         枚举、结构体、类都可以定义计算属性
     
     
     计算属性必须用var修饰,不能用let,
        let代表常量:值是一成不变的,
        计算属性的值是可能发生变化的(即使是只读计算属性)
     */
    
    
    //1、结构体的计算属性
    struct Circle{
        //半径 存储属性
        var radius:Int = 0
        
        //计算属性 本质是方法 不占用实例的内存 定义计算属性必须用var 不能使用let
        var diameter:Int{
            set(nValue){
                radius = nValue / 2
            }
            get{
                return radius * 2
            }
        }
        
        //也简写成这种格式
        var diameter2:Int{
            set{
                //set 传入的新值默认叫做newValue 也可以自定义
                radius = newValue/2
            }
            get{
                radius*2
            }
        }
        
        //只读计算属性:只有get 没有set
        var diameter3:Int{
            get{
                radius*2
            }
        }
        
        //只读计算属性:可以简写
        var diameter4:Int{ radius*2 }
        
        //只有set 会报错 Variable with a setter must also have a gette
//        var diameter5:Int{
//            set{
//                radius = newValue / 2
//            }
//        }
    }
    
    
    //创建并初始化一个实例
    var c = Circle(radius: 10)

    
    
    /**
     ->  0x1000172e3 <+211>: callq  0x100017950
     ; diameter.setter : Swift.Int in Circle #1 in LCClientDemo_commond.computedPropertyExplain() -> () at 8-01-属性、汇编分析inout本质.swift:115
    
     c.diameter= 本质是方法调用 setter
     */
    c.diameter = 30//15 30
    
    
    
    /**
     ->  0x100017310 <+256>: callq  0x100017900
     ; diameter.getter : Swift.Int in Circle #1 in LCClientDemo_commond.computedPropertyExplain() -> () at 8-01-属性、汇编分析inout本质.swift:118

     =c.diameter本质是方法调用 getter
     */
    print(c.radius,c.diameter)
}

rawValue的本质是

func enumRawValueExplain(){
    

    enum Season:Int{
        case spring = 1,summer,autumn,winter
        
        //enum 的 rawValue的本质是计算属性
        var rawValue: Int{
            get{
                switch self {
                case .spring:
                    return 10
                case .summer:
                    return 20
                case .autumn:
                    return 30
                case .winter:
                    return 40
                }
            }
        }
    }
    
    
    /**
     ->  0x10001798a <+10>:  callq  0x1000181f0
     ; rawValue.getter : Swift.Int in Season #1 in LCClientDemo_commond.enumRawValueExplain() -> () at <compiler-generated>

     */
    let value = Season.spring.rawValue
    print(value)
}

延迟存储属性

func lazyStoredProperty() -> Void {
    
    
    //使用lazy可以定义一个延迟存储属性,在第一次用到属性的时候才会进行初始化
    
    
    //1、lazy使用
    do{
        class Car{
            init() {
                print("Car init!")
            }
            func run() -> Void {
                print("Car is running !")
            }
        }
        
        class Person{
            lazy var car = Car()
    //        var car = Car()

            init() {
                print("Person init !")
            }
            func goOut() -> Void {
                car.run()
            }
        }
        
        let p = Person()
        p.goOut()
        
        //没有lazy 修饰的情况
        /**
         Car init!
         Person init !
         Car is running !
         */
        
        //有lazy修饰的情况
        /**
         Person init !
         Car init!
         Car is running !
         */
    }
   

    
    //2、lazy使用
    do{
        struct Point{
            var x = 0
            var y = 0
            lazy var z = 0
        }
        
        /**
         有lazy修饰 实例使用let 时 存储属性会进行取值赋值操作时会报错
         Cannot use mutating getter on immutable value: 'po' is a 'let' constant
         */
        //let po = Point()
        
        /**
         当结构体包含一个延迟存储属性时,只有var才能访问延迟存储属性
         因为延迟存储属性初始化时需要改变结构体的内存
         */
        var po = Point()
        let z = po.z
        print(z)
    }
    
    //3、总结
    /**
     lazy 属性必须var 不能是let
     let 必须在实例的初始化方法完成之前就拥有值
     
     当结构体包含一个延迟存储属性时,只有var才能访问延迟存储属性
     因为延迟存储属性初始化时需要改变结构体的内存

     多线程同时第一次访问lazy属性无法保证属性只被初始化一次
     */
}

属性观察器

func propertyObserver() -> Void {
    
    /**
     可以为非lazy的var存储属性设置属性观察器
     willSet会传递新值,默认叫newValue
     didSet会传递旧值,默认叫oldValue
     在初始化器中设置属性值不会触发willSet和didSet
     在属性定义时设置初始值也不会触发willSet和didSet
     */
    
    
    
    //1、属性观察器
    do{
        print("---------1----------")
        struct Circle{
            //必须是var修饰的存储属性才有 willSet 和 didSet
            var radius:Int{
                willSet{
                    print("willSet",newValue)
                }
                didSet{
                    print("didSet",oldValue,radius)
                }
            }
            init() {
                //初始化器中不会触发willSet 和 didSet
                self.radius = 1
                print("circle init")
            }
        }
        
        //circle init
        var r = Circle()
        
        //willSet 20
        //didSet 1 20
        r.radius = 20
    }
    
    
    //2、局部变量也有属性观察器 和 计算属性
    do{
        print("---------2----------")
        
        //属性观察器
        var a = 10{
            willSet{
                print("willSet",newValue)
            }
            didSet{
                print("didSet",oldValue,a)
            }
        }
        a = 100
        
        
        //计算属性
        var b:Int{
            set{
                print("b",newValue)
            }
            get{
                return 10
            }
        }
        
        //b 20
        b = 20
        
        print(b)//10
    }
    
    //3、全局变量也有属性观察器 和 计算属性
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.