swift 属性2

83 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

使用方式:
  • 1、类中定义的存储属性
  • 2、通过类继承的存储属性
class HJBoy : HJPerson{
    override var age: Int{
        //新值存储之前调用
        willSet{
            print("willSet newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("didSet oldValue (oldValue)")
        }
    }
}
  • 3、通过类继承的计算属性
class HJPerson{
    var age: Int = 18
    
    var age2: Int {
        get{
            return age
        }
        set{
            self.age = newValue
        }
    }
}
var t = HJPerson()

class HJBoy : HJPerson{
    override var age: Int{
        //新值存储之前调用
        willSet{
            print("willSet newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("didSet oldValue (oldValue)")
        }
    }
    
    override var age2: Int{
        //新值存储之前调用
        willSet{
            print("willSet newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("didSet oldValue (oldValue)")
        }
    }
}
属性观察者的触发时机:

以下代码中,init方法中设置name,是否会触发属性观察者?

class HJPerson{
    var name: String = "测试"{
        //新值存储之前调用
        willSet{
            print("willSet newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("didSet oldValue (oldValue)")
        }
    }
    
    init() {
        self.name = "KC"
    }
}

运行结果发现,并没有走willSet、didSet中的打印方法,所以有以下结论:

  • 在init方法中,如果调用属性,是不会触发属性观察者的
  • init中主要是初始化当前变量,除了默认的前16个字节,其他属性会调用memset清理内存空间(因为有可能是脏数据,即被别人用过),然后才会赋值

【总结】:初始化器(即init方法设置)和定义时设置默认值(即在didSet中调用其他属性值)都不会触发

【问题1】:子类和父类的计算属性同时存在didset、willset时,其调用顺序是什么?
import Foundation

class HJPerson {
    var age: Int = 18{
        //新值存储之前调用
        willSet{
            print("父类 willSet newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("父类 didSet oldValue (oldValue)")
        }
    }
    
    var age2: Int {
        get{
            return age
        }
        set{
            self.age = newValue
        }
    }
}


class HJSon: HJPerson{
    override var age: Int{
        //新值存储之前调用
        willSet{
            print("子类 newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("子类 didSet oldValue (oldValue)")
        }
    }
    
}

var t = HJSon()
t.age = 20

//  ------打印:
子类 newValue 20
父类 willSet newValue 20
父类 didSet oldValue 18
子类 didSet oldValue 18

【结论】:对于同一个属性,子类和父类都有属性观察者,其顺序是:先子类willset,后父类willset,再父类didset, 子类的didset,即:子父 父子,记忆:父总是让着子

【问题2】:子类调用了父类的init,是否会触发观察属性?

import Foundation

class HJPerson {
    var age: Int = 18{
        //新值存储之前调用
        willSet{
            print("父类 willSet newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("父类 didSet oldValue (oldValue)")
        }
    }
    
    var age2: Int {
        get{
            return age
        }
        set{
            self.age = newValue
        }
    }
}


class HJSon: HJPerson{
    override var age: Int{
        //新值存储之前调用
        willSet{
            print("子类 newValue (newValue)")
        }
        //新值存储之后调用
        didSet{
            print("子类 didSet oldValue (oldValue)")
        }
    }
    
    override init() {
     super.init()
     self.age = 20
    }
}
//****** 打印结果 ******
子类 willSet newValue 20
父类 willSet newValue 20
父类 didSet oldValue 18
子类 didSet oldValue 18
  • 从打印结果发现,会触发属性观察者,主要是因为子类调用了父类的init,已经初始化过了,而初始化流程保证了所有属性都有值(即super.init确保变量初始化完成了),所以可以观察属性了

三、 类型属性

  • 1、使用关键字static修饰,且是一个全局变量
  • 2、类型属性必须有一个默认的初始值
  • 3、类型属性只会被初始化一次

举例:

class CJLTeacher{
    static var age: Int = 18
}
// **** 使用 ****
var age = CJLTeacher.age