来源

Official documents

 

属性分为计算属性、存储属性、类型属性

另外,还可以定义属性监视器来监控属性值的变化。属性监视器可以添加到自己写的存储属性上,也可以添加到从父类继承的属性上。

 

存储属性

简单来说,一个存储属性就是存储在特定类或结构体的实例里的一个常量或变量。

下面的例子定义了一个名为FixedLengthRange的结构体,他描述了一个在创建后无法修改值域宽度的区间:

struct FixedLengthRange { 
    var firstValue: Int 
    let length: Int 
} 
var range = FixedLengthRange(firstValue: 0, length: 3) 
// 该区间表示整数0,1,2 
range.firstValue = 6 
// 该区间现在表示整数6,7,8 ,因为length是常量属性,所以之后无法修改它的值。

 

常量和存储属性

// 如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性:
let range = FixedLengthRange(firstValue: 0, length: 4) 
// 该区间表示整数0,1,2,3 
range.firstValue = 6 
// 尽管firstValue是个变量属性,这里还是会报错 

这种行为是由于结构体(struct)属于值类型。当值类型的实例被声明为常量的时候,它的所有属性也就成了常量。

属于引用类型的类(class)则不一样,把一个引用类型的实例赋给一个常量后,仍然可以修改实例的变量属性。

 

延迟存储属性

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

注意:必须将延迟存储属性声明成变量(使用var关键字),因为属性的值在实例构造完成之前可能无法得到。

 

class DataImporter { 
    /* 
    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("Some more data")
// DataImporter 实例的 importer 属性还没有被创建 

  

只有使用了lazy,importer属性只有在第一次被访问的时候才被创建。比如访问它的属性fileName时:

println(manager.importer.fileName) 
// DataImporter 实例的 importer 属性现在被创建了 
// 输出 "data.txt” 

 

计算属性

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

struct Point { 
    var x = 0.0, y = 0.0 
} 
struct Size { 
    var width = 0.0, height = 0.0 
} 
struct Rect { 
    var origin = Point()  // 存储属性
    var size = Size()    // 存储属性
    var center: Point {   // 计算属性
      get { 
          let centerX = origin.x + (size.width / 2) 
          let centerY = origin.y + (size.height / 2) 
          return Point(x: centerX, y: centerY) 
      } 
      set(newCenter) { 
          origin.x = newCenter.x - (size.width / 2) 
          origin.y = newCenter.y - (size.height / 2) 
      } 
  } }

便捷 set 声明

如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称newValue。下面是使用了便捷 setter 声明的Rect结构体代码:
struct AlternativeRect { 
    var origin = Point() 
    var size = Size() 
    var center: Point { 
      get { 
          let centerX = origin.x + (size.width / 2) 
          let centerY = origin.y + (size.height / 2) 
          return Point(x: centerX, y: centerY) 
      } 
      set { 
          origin.x = newValue.x - (size.width / 2) 
          origin.y = newValue.y - (size.height / 2) 
      } 
    } 
} 

 

只读计算属性

只有 getter 没有 setter 的计算属性就是只读计算属性。

注意:必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。

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

struct Cuboid { 
    var width = 0.0, height = 0.0, depth = 0.0 
    var volume: Double { 
        return width * height * depth 
    } 
} 
let four = Cuboid(width: 4.0, height: 5.0, depth: 2.0) 
println("\(four.volume)") 
// 输出 "40.0" 

那有没有只写属性呢?

 

属性监视器

属性观察器分为两种:

  • willSet(属性值改变前触发)-默认名称newValue
  • didSet(属性值改变后触发)-默认参数名oldValue

注意:willSetdidSet观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用

class StepCounter {
    var totalSteps: Int = 0 {
        willSet {
            println("About to set totalSteps to \(newValue)")
        }
        didSet {
            if totalSteps > oldValue  {
                println("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

 

全局变量和局部变量

  • 全局变量是在函数、方法、闭包或任何类型之外定义的变量
  • 局部变量是在函数、方法或闭包内部定义的变量

注意:

全局的常量或变量都是延迟计算的,跟延迟存储属性相似,不同的地方在于,全局的常量或变量不需要标记lazy特性。
局部范围的常量或变量不会延迟计算

类型属性(相当于静态属性)

  1. 定义类型属性的格式为 static var 属性名 : 类型{get/set {}} 
  2. 对于引用类型,类型属性必须使用计算属性,不能是存储属性,且必须是变量
  3. 对于struct、enum必须给类型属性制定默认值,因为类型属性不属于实例的范畴,不能使用任何的构造器赋值
类型属性语法

 

struct SomeStructure { // 结构体
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration { // 枚举
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass { // 类
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

注意:例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性

获取和设置类型属性的值,通过类名直接访问:

println(SomeClass.computedTypeProperty) 
// 输出 "42" 
 
println(SomeStructure.storedTypeProperty) 
// 输出 "Some value." 
SomeStructure.storedTypeProperty = "Another value." 
println(SomeStructure.storedTypeProperty) 
// 输出 "Another value.” 

  

结构体中的类型属性:

struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
        didSet {
            if currentLevel > AudioChannel.thresholdLevel {
                // 将新电平值设置为阀值
                currentLevel = AudioChannel.thresholdLevel
            }
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                // 存储当前电平值作为新的最大输入电平
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
            // 这段代码的作用是控制currentLevel的值不超过10
        }
    }
}

 

var leftChannel = AudioChannel()
var rightChannel = AudioChannel()

leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
// prints "7"
print(AudioChannel.maxInputLevelForAllChannels)
// prints "7"

rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
// prints "10"
print(AudioChannel.maxInputLevelForAllChannels)
// prints "10"

 

let 常量
var 变量

存储属性 var/let 属性监视器
计算属性 var

类型属性
    引用类型:如class
        计算属性
    
    值类型:如struct、enum
        计算属性/存储属性

 

2015-03-21

19:44:13

posted on 2015-03-21 19:44  道无涯  阅读(154)  评论(0编辑  收藏  举报