Swift 学习笔记 「属性」

#Program

存储属性

struct FixedLengthRange {
    var firstValue: Int
    let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 该区间表示整数0,1,2
rangeOfThreeItems.firstValue = 6
// 该区间现在表示整数6,7,8
  • 常量和存储属性

    如果创建了一个结构体的实例并赋值给一个常量,那么就无法修改实例的任何属性,即使定义了变量存储属性

      let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
      // 该区间表示整数0,1,2,3
      rangeOfFourItems.firstValue = 6
      // 尽管 firstValue 是个变量属性,这里还是会报错
    
  • 延迟存储属性

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

      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 属性还没有被创建
    

计算属性

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)
    }
    }
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
    size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 输出 "square.origin is now at (10.0, 10.0)”
  • 便捷 setter 声明

    如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue。

      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 的计算属性就是只读计算属性,只读计算属性的声明恩可以去掉 get 关键字和话括号:

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

属性监视器

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

  • willSet 在设置新的值之前调用,会将新的属性值作为固定参数传入,默认名为 newValue
  • didSet 在新的值被设置之后立即调用,会将旧的属性值作为参数传入,默认名为 oldValue

willSet 和 didSet 监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用

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

类型属性

类型属性用于定义特定类型所有实例所共享的数据。

  • 类型属性语法

    使用关键字 static 来定义值类型的类型属性,关键字 class 来为类定义类型属性

      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 值
          }
      }
    
  • 示例

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

END