Swift10-属性

存储属性、计算属性、属性观察器、全局变量和局部变量、类型属性。

 

属性将值根特定的类、结构或枚举关联。存储属性存储常量或变量作为实例的一部分,而计算属性计算(不是存储)一个值。计算属性可以用于类、结构体和枚举,存储属性只能用于类和结构体。

 

存储属性和计算属性通常与特定类型的实例关联。但是,属性也可以直接作用于类型本身,这种属性称为类型属性。

 

另外,可以定义属性观察器来监控属性值的变化,以此来触发一个自定义的操作。属性观察器可以添加到自己定义的存储属性上,也可以添加到从父类继承的属性上。

 

存储属性:

一个存储属性就是存储在特定类或结构体实例里的一个常量或变量。存储属性可以是变量存储属性或常量存储属性。

可以在定义存储属性的时候指定默认值。也可以在构造过程中设置或修改存储属性的值,甚至修改常量存储属性的值。

 

常量结构体的存储属性:

如果创建了一个结构体的实例并将其赋值给一个常量,则无法修改该实例的任何属性,即使变量存储属性也不行。

struct a{var ai:Int}

let at=a(ai:10)  //

 

延迟存储属性:

延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用lazy来标示一个延迟存储属性。

必须将延迟存储属性声明成变量(var),因为属性的初始值可能在实例构造完成之后才会得到。而常量属性在构造过程完成之前必须要有初始值。

 

延迟属性很有用,当属性的值依赖于在实例的构造过程结束后才会知道影响值的外部因素时,或者当获得属性的初始值需要复杂或大量计算时,可以只在需要的时候计算它。

class DataImporter{var fileName="data.txt"}

class DataManager{

  lazy var importer=DataImporter()

  var data=[String]()

}

let manager=DataManager()

manager.data.append("Some data")

manager.data.append("More data")

//此时DataImporter实例的importer属性还没有被创建

print(manager.importer.fileName)

//此时用到DataImporter实例的importer属性,所以此时才去创建

 

如果一个被标记为lazy的属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次。

 

Swift中的属性没有对应的实例变量,属性的后端存储也无法直接访问。

 

 

计算属性:

除存储属性外,类、结构体和枚举可以定义计算属性。计算属性不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和设置其它属性或变量的值。

计算属性不能有默认值或构造时赋值。

struct a{

  var b:Int=9

  var c:Int{

    get{

      return b+1

    }

    set{

      b=newValue-1

    }

  }

}

//get用于获取c这个属性时使用(print(c)),计算b+1并返回给调用

//set用于设置c这个属性时使用(c=20),set可指定一个新变量名称临时表示set(newC),默认是newValue

 

只读计算属性:

只有getter没有setter的计算属性就是只读计算属性。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。

只读计算属性的声明可以去掉get关键字和花括号:

struct t{

  var a:Int

  var b:Int{

    return a+1

  }

}

 

属性观察器:

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。

可以为除了延迟存储属性之外的其它存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性)添加属性观察器

计算属性中不能加上属性观察器。

可以为属性添加如下的一个或全部观察器:

1)willSet,在新的值被设置之前调用

2)didSet,在新的值被设置之后立即调用

willSet观察器会将新的属性值作为常量参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数默认为newValue使用。

didSet观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。如果在didSet中再次对该属性赋值,那么新值会覆盖旧的值。

(但didSet观察器中对被观察的值的设置不会再次递归调用观察器)

观察器不会在属性默认赋值和构造赋值时被调用。

 

注意:父类的属性在子类的构造器中被赋值时,它在父类中的willSet和didSet观察器会被调用,随后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器不会被调用。

 

 

全局变量和局部变量:

计算属性和属性观察器所描述的功能也可用于全局变量和局部变量。全局变量是在函数、方法、闭包或任何类型之外定义的变量。局部变量是在函数、方法或闭包内部定义的变量。

在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器。

 

全局的常量或变量都是延迟计算的,根延迟存储属性相似,不同之处在于,全局的常量或变量不需要标记lazy修饰符。

局部范围的常量或变量从不延迟计算。

 

 

类型属性:

实例属性属于一个特定类型的实例,没创建一个实例,都拥有属于自己的一套属性值,实例之间的属性相互独立。

也可以为类型本身定义属性,无论创建多少个该类型的实例,这些属性都只有唯一一份。这种属性就是类型属性。

类型属性用于定义某个类型所有实例共享的数据,比如所有实例都能用的一个常量或变量。

存储型类型属性可以是变量或常量,计算型类型属性根实例的计算型属性一个只能被定义成常量。

 

注意:跟实例的存储型属性不同,必须给存储型类型属性指定默认值,因为类型本身没有构造器,也就无法在初始化过程中使用构造器给类型属性赋值。

存储型类型属性是延迟初始化的,它们只有在第一次被访问的时候才会被初始化。即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化,并且不需要对其使用lazy修饰符。

 

类型属性语法:

Swift中,类型属性是作为类型定义的一部分写在类型最外层的花括号内,因此它的作用范围也就在类型支持的范围内。

使用关键字static来定义类型属性。

在为类定义计算型类型属性时,可以改用关键字class来支持子类对父类的实现进行重写。

class SomeClass{

  static var storedType="Some value"

  static var computedType:Int{

    return 27

  }

  class var overrideableComputedType:Int{

    return 107

  }

}

 

获取和设置类型属性的值:

跟实例一样,类型属性也是通过点运算符来访问的。但是,类型属性是通过类型本身来访问,而不是通过实例。

print(SomeStructure.storedType)

 

posted @ 2020-05-07 16:32  吉吉boy  阅读(168)  评论(0编辑  收藏  举报