美文网首页
认识Swift系列8之属性

认识Swift系列8之属性

作者: Niuszeng | 来源:发表于2019-07-12 15:40 被阅读0次
    struct Car {
        init() { print("Car int") }
        func run() { print("Car run") }
    }
    
    struct Circle {
        
        // 1.存储属性
        // 存储属性占用对象内存空间,用来存储对象的某个特定值
        var radius: Double
        
        // 2.延迟存储属性
        // 当某个属性希望在使用到的时候再创建时,可以使用 lazy 修饰
        // lazy表示延迟加载,即使用到的时候在加载
        // 如下列属性car,有可能在使用Circle对象的过程中,一直用不到car对象
        // 如果不延迟,Circle对象一创建car对象也创建,造成内存空间浪费
        //
        // 注意1:lazy只能使用var声明,因为let要求在变量初始化完成之前就拥有值
        // 注意2:lazy不能保证线程安全,多小线程访问的时候可能导致创建多个对象
        lazy var car = Car()
        // 若要线程安全,可这样考虑
        lazy var car1: Car = {
            Car()
            /** 在这里来做线程安全的事(伪代码)
             dispatch_once {
                Car()
             }
             */
        }()
        // 注意3,当结构体包含延迟存储属性的时候,只有var对象才能访问延迟存储属性
        //       因为延迟存储属性初始化时需要改变结构体内存,而结构体的创建的实例
        //       如果使用let初始化,则表明内存不能再被更改,因此结构体包含延迟存储
        //       属性的时候,职能用var修饰结构创建出来的对象
        // 若是类则没有这个限制,因为let只修饰p变量,不修饰堆空间p对象内存
        /**
         struct Point {
            var x = 0
            var y = 0
            lazy var z = 0
         }
         
         let p = Point()
         p.z // 这句代码会初始化z改变结构体内存,和let冲突
         
         // 应该这样创建对象
         var p = Point()
         p.z
         */
        
        // 3.计算属性
        // 计算属性不占用内存空间,它类只有中Setter和Getter方法
        // 本质上该属性就是一对Setter和Getter方法而已
        // 如果要让计算属性只读,只提供getter(get)方法即可
        //
        // 注意:如果提供了set,则必须有get,即不能只提供写而不提供读
        // 计算属性职能用var定义,计算属性的值可能发生改变,即使是只读的也可能发生改变
        //
        // set方法中会默认提供newValue形参,如要该表只需要明确声明形参 set(theValue)
        // get方法中会默认提供newValue形参,如要该表只需要明确声明形参 set(theValue)
        var diameter: Double {
            set {
                radius = newValue / 2
            }
            get {
                return radius * 2
            }
        }
        
        // 枚举中rawValue就是计算属性实现
        enum TestEnum: Int {
            case test1 = 1, test2, test3
            var rawValue: Int {
                // 只有get方法,省略get
                switch self {
                case .test1: return 1
                case .test2: return 2
                case .test3: return 3
                }
            }
        }
        
        // 4.属性观察期(类似OC的KVO)
        // 这个属性咋一看很想计算属性
        // 同样 willSet 和 didSet自带默认参数newValue 和 oldValue
        // newValue是新设置的值,oldValue是以前的值
        //
        // 注意1:在初始化器(init)中设置属性值,不会引起willSet、didSet调用
        //      原因很简单:在初始化器中监听属性值变化没有意义,监听的目的是为了
        //      拦截或做并做某些改变,初始化的时候我们本是就可以控制该行为
        // 注意2:在定义的时候设置初始值也不会触发willSet、didSet,和注意1很像
        //      在这个位置监听拦截也没有意义,因为这里行为也是我们控制的
        // 注意3:属性监听器(willSet、didSet)和计算属性(get、set)不能共存
        //      即存储在get或set、就不能存在willSet或didSet,这两对方法相互
        //      排斥,其实原因也容易理解,既然我们都可以控制set和get了
        //      那么willSet、didSet将变得毫无意义
        //
        // 注意4:属性监听器更准确的说法(我认为)叫监听器,因为它不仅可以监听
        //       成员属性变化,还可以监听全局变量、局部变量等的变化
        /**
         // 全局变量
         var num: Int {
            get { 10 }
            set { if newValue < 0 // code... }
         }
         
         // 局部变量
         func test() {
             var num: Int {
                 get { 10 }
                 set { if newValue < 0 // code... }
             }
         }
         */
        var perimeter: Double = 10 {
            willSet {
                print("perimeter:\(newValue)")
            }
            didSet {
                print("perimeter:\(oldValue)")
            }
        }
        
        // 5.类型属性(Type Property 类属性)
        // 实例属性,每个实例都拥有一份该属性
        // 类属性,每个类拥有一份,该类的素所有实例共用一份
        // 存储类属性,本质上是全局变量,只是访问权限被限定到该类
        // 实际上类属性就是全局变量,而起访问权限的限制事实上是编译器的语法糖而已
        //
        // 修饰符用  结构体:static  类:static、class
        // static修饰的子类不能再重写(结构体不支持继承)
        // class修饰的子类可以重写
        // 不同于存储实例属性,类属性要求必须更定初始值,因为init并不会初始化类属性
        /**
         class let prperty1 = 0
         static var prperty2 = 0
         */
        //
        // 注意1,类存储属性默认已经是lazy,并且线程安全(底层用dispatch_once实现)
        //      这样可以保证只初始化一次
        // 注意2,类存储类型属性,可以使let,因为类属性的本质是全局变量,和当前类或者
        //       实例变量的内存结构没关系,即使延迟初始化也不会对当前实例造成影响,只是
        //       只不过let让其只能初始化一次而已
        static let property1 = 0
        static var property2 = 0
        
        // 6.计算类型类属性
        static var property3: Int {
            set { property2 = newValue }
            get { return property2 }
        }
        
        init(radius: Double) {
            self.radius = radius
        }
    }
    
    let c = Circle(radius: 1)
    print(c.radius)
    print(c.diameter)

    // 6.一个简单的单例设计
    class FileManager {
        // 第一种
        public static let shared = FileManager()
        
        // 第二种
        public static let shared1 = { () -> FileManager in
            let instance = FileManager()
            // your code ...
            // 由于static特性,这里实际上已经是线程安全
            return instance;
        }()
        
        private init(){}
    }
    
    // 7.枚举可以定义 static类属性(不能定义实例属性)
    enum TestEnum: String {
        static var property1 = 0
        static var property2: Int {
            set { property1 = newValue }
            get { return property1 }
        }
        case A,B,C,D
    }

相关文章

网友评论

      本文标题:认识Swift系列8之属性

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