属性

一.跟实例相关的属性

  1. 实例:一个接收了结构体/类/枚举的赋值的变量或者常量。
  2. 属性:存在于结构体/类/枚举中的变量或者常量。
  3. 分为两大类:
  • 存储属性:类似与成员变量的概念,存储在实例的内存中。结构体和类可以定义存储属性,枚举不可以,因为枚举内存中存储的是关联值或者keys,不直接存储数据。
  • 计算属性:本质是方法,计算属性不占用实例的内存,给计算属性赋值就会默认调用其中的set方法,获取计算属性的值会默认调用其中的get方法。枚举,结构体,类,都可以定义计算属性。
struct Circle{
    var radius : Double
    var diameter : Double{ //本质是方法,不储存在Circle的空间中。
        set{
            radius = newValue / 2
        }
        get{
            radius * 2
        }
    }
}
var c = Circle(radius: 10)
c.radius = 11
c.diameter = 55 //给计算属性赋值,调用其set函数
print(c.radius) // 27.5
c.radius = 11
print(c.diameter) // 22 获取计算属性,调用其get函数

存储属性:

  1. 在创建类或者结构体的实例时,必须为所有存储属性设置一个合适的初始值。
  • 可以在init中为存储属性设定一个初始值。
  • 可以在存储属性的定义中设置初始值。

计算属性:

  1. set传入的新值默认叫做newValue,也可以自定义。
  2. 只读计算属性:只有get,没有set。可以省略get,直接用大括号包含方法。
  3. 定义计算属性只能用var,不能用let,计算属性的值很可能是会发生变化的,即使是只读属性。

枚举rawValue的本质:

  1. 枚举中原始值的获取是以设定计算属性与switch来获取的rawValue的,获取原始值是调用了其中的get方法。所以rawValue是一个只读的计算属性。

延迟存储属性

  1. 使用lazy定义一个延迟存储属性,第一次用到属性的时候才会进行初始化。只能用var定义lazy属性,因为let常量在实例初始化完成之前需要有值,与lazy矛盾。
  2. 如果多线程同时第一次访问lazy属性,就无法保证属性只被初始化一次,所以lazy不是线程安全的。
  3. 当结构体包含一个延迟存储属性时,只有var才能访问延迟存储属性,因为延迟属性初始化时需要改变结构体内存。

属性观察器

  1. 可以为非lazy的var的存储属性设置属性观察器。
  2. 属性观察器:可以监听存储属性的修改, 新赋值会传给willset函数的newValue,当newValue获得值之后,会执行didSet函数,并将存储属性修改前的值给到didSet中的oldValue
  3. 在初始化器中设置属性值不会触发属性观察器。
  4. 属性观察器也可以使用在全局变量以及局部变量中。

inout

  1. 本质:引用传递,传递了一个值的地址值。
  2. inout对于有属性观察器的存储属性:
  3. inout对计算属性:计算属性本身没有内存地址,计算属性传给inout时,先调用get方法,将get方法的返回值放到一块临时存储空间,再用inout的新值覆盖局部变量,完成数值转换
  4. inout对于带有属性观察器的属性:首先将存储属性的值给一个局部变量,将局部变量的地址值传入inout所在函数,输出输出函数将会修改局部变量,在将局部变量的值赋值给存储属性,所以带有属性观察器的属性,输入输出函数对其内存的修改不是发生在函数中,而是在函数调用完毕之后 其本质是为了触发属性观测器。
  5. 输入输出方法只是单纯的进行一个值地址的传递。
  6. 总结:
  • 如果实参有物理内存地址,且没有设置属性观察器,直接将实参的内存地址传入函数(实参进行引用传递)
    1. 如果实参是计算属性或者设置了属性观察器,采取Copy In Copy Out的做法:调用该函数时,先复制实参的值,产生副本,副本就是一个局部变量【相当于get操作】
    1. 将副本内存(局部变量)地址传入inout函数(副本进行了引用传递),在inout内部可以修改函数副本的值。
    1. inout函数将局部变量返回后,再将此值覆盖实参的值【相当于set】

类型属性(Type Property)

属性可分为:

  1. 实例属性(Instance Property):只能通过实例去访问
  • 存储实例属性(Stored Instance Property):存储在实例的内存中,每个实例都有1份单独的空间。枚举无法定义,因为其内存是放在实例的单独空间中,枚举中的内存是用来存储case与关联值的。
  • 计算实例属性(Computed Instance Property):如计算属性,本质是方法。
  1. 类型属性(Type Property):只能通过类型去访问
  • 存储类型属性(Stored Type Property):整个程序运行中只有一份内存,类似于全局变量。在属性前加static将其转变为类型属性。在C++中可以用实例访问类型属性,在swift中只能各访问各的。存储类型属性的内存存放在
  • 计算类型属性(Computed Type Property):只读计算属性,也是方法。
  • 在类中可以用class定义类型属性,在结构体中只能用static
  • 不同于实例存储属性,必须给存储类型属性初始值。因为类型属性没有init方法。
  • 存储类型属性默认为lazy,在第一次调用时候才会初始化,且对多线程访问时,也只会初始化一次。但是不同于lazy,类型属性是可以用let常量表示的。
  • 枚举类型也可以定义类型属性, 因为类型属性的内存不占用枚举类型。
  1. 单例模式:使得只初始化一次,其他调用使用同样的值。
class FileManager{
	public static let shared = FileManager()
	private init(){}
	func open(){}
	func close(){}
}

FileManager.shared.open

二.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值