存储属性和计算属性的区别
如图来说radius是存储属性,diam是计算属性,具体的区别在于内存和调用上面
1.存储内存是需要结构体的内存来存储,但计算属性的函数是存储在函数段,本身是不占用变量内存的
2.初始化,不管是结构体还是类,都强调要初始化值,但计算属性不初始化也没事
3.调用,从汇编源码来看,存储属性是直接往地址写入值,而计算是调用这个set get函数,然后函数写啥执行啥
4.存储属性是不能在enum里面用的,因为之前看过枚举,里面是没地方放这个新属性,但支持结构体和类,计算属性,结构体,类,枚举三者都支持
可以看出diam没初始化程序也依然运行了,circle的地址打印出来最近的32个字节,也只有前8个字节有值, 里面的值是浮点数的表示形式,所以可证明计算属性确实不占用枚举内存,然后打断点去汇编看
可以看出diam的本质就是函数,赋值就走set,取值就走get
枚举的原始值
计算属性可以没有set,但必须有get
可以自定义个rawValue,然后覆盖掉原来的rawValue,其实实际的rawValue也差不多
可以看出官方的定义rawValue就是只读的计算属性,那么这个rawValue的值不需要存储空间就好理解了
延迟存储属性
延时属性其实也没啥,就是加个lazy之后初始化的时候不执行,只有真正用到才会执行
比如上图所示,只有调用的时候才会执行
注意点:lazy是不能修饰let,因为lazy的目的就是延迟再初始化,而let在初始化之前就必须有值,lazy也不是线程安全的(多线程再细说)
属性观察器
属性观察器和OC的kvo很像
限制:属性观察器不能给计算属性提供,我猜想是没有必要,set get都能进行监听
从汇编来看
在设置了属性监听后,会生成一个setter函数然后在里面做处理并调用willset和didset,全局变量,局部变量也是可以设置的,虽然是用成员变量举例
属性再细分
属性其实还可以再细分,分为类型属性和实例属性
像刚才只能通过类或者结构体实例对象去访问的,就叫实例属性,而通过类名或者结构体去访问的称为类型属性
实例属性前面讲过就不赘述了
类型属性就是前面加static,然后必须初始化,访问也必须用类名来访问,static默认是lazy属性,但是不同于lazy的是,他可以用let修饰
单例模式
这个属性很适合做单利了,比如
全局范围内只需要创建一次的FileManager,哪里要使用就直接通过公共模块获取就好了