码迷,mamicode.com
首页 > 其他好文 > 详细

第十二章.属性

时间:2015-03-21 21:06:58      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:

来源

 

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

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

 

存储属性

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

下面的例子定义了一个名为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 += "Some data" 
manager.data += "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. 定义类属性的格式为 class var 属性名 : 类型{get/set {}} 
  2. 对于引用类型,类属性必须使用计算属性,不能是存储属性
  3. 类属性必须被定义为变量类型,因为类属性是计算类型,计算类型必须是变量
  4. 必须给类属性制定默认值,因为类属性不属于实例的范畴,不能使用任何的构造器赋值
类型属性语法
struct SomeStructure { // 结构体
    static var storedTypeProperty = "Some value." 
    static var computedTypeProperty: Int { 
    // 这里返回一个 Int 值 
    } 
} 
enum SomeEnumeration { // 枚举
    static var storedTypeProperty = "Some value." 
    static var computedTypeProperty: Int { 
    // 这里返回一个 Int 值 
    } 
} 
class SomeClass {   // 类
    class var computedTypeProperty: Int { 
    // 这里返回一个 Int 值 
    } 
} 

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

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

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   } } }
rightChannel.currentLevel = 11  
println(rightChannel.currentLevel)  
// 输出 "10"  
println(AudioChannel.maxInputLevelForAllChannels)  
// 输出 "10"  

 

2015-03-21

19:44:13

第十二章.属性

标签:

原文地址:http://www.cnblogs.com/huangzx/p/4356074.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!