美文网首页
Properties

Properties

作者: 夜雨聲煩_ | 来源:发表于2017-10-30 18:28 被阅读0次
    • 属性分为类型属性和实例属性。使用staticclass关键字修饰的属性为类型属性,否则为实例属性。其中staticclass两个关键字的区别在于,static修饰的类型属性不能重载。而class属修饰的类型属性在子类中可以使用override class来进行重载。
    • 属性分为存储属性和计算属性两种,类和结构体都可以拥有这两种属性,但是枚举只能有计算属性。

      存储属性用来例如控件创建等,特点是有=。而计算属性是用来获取计算值,特点是getset

    • 不同于OC中的属性和实例变量的两个概念,swift中只有属性。实际上swift中有存储属性和计算属性,存储属性用来存储相应值,而计算属性会提供一个getter方法,和一个可选的setter方法。
    • 可以使用let常量和var变量来修饰属性,其中变量属性可以随时修改,而常量属性只能在初始化的时候赋值。

      注意:计算属性,包括只读计算属性,都只能用var来修饰。

    • 结构体的实例需要定义成变量才可以修改其变量属性,否则会报错。而类的实例不需要定义成变量(即常量情况下)也可以修改其变量属性。,区别原因的根本在于值类型和引用类型的不同。
    • 变量总需要使用lazy定义为延迟属性,因为变量可以在初始化过程中不赋值,而是在初始化结束赋值并使用。而常量不可以定义为延迟属性,因为常量在初始化过程中就赋值完成了。
    • 使用lazy实现存储属性的懒加载
      //Lazy Stored Properities
      class DataImporter {
          var fileName = "data.txt"
      }
      
      class DataManager {
          lazy var importer = DataImporter()
          var data = [String]()
      }
      
      //直到这里DataImporter()才会执行。
      print(manager.importer.filename)
      // the DataImporter instance for the importer property has now been created
      // Prints "data.txt"
      

      注意:多线程同时访问未被初始化的lazy属性时,可能会出现多次初始化的问题

    • 计算属性不直接储存值,而是通过getter方法通过其他存储属性计算返回值,通过setter方法计算赋给其他存储属性值
       struct Rect {
          var origin = Point()
          var size = Size()
          //不需要存储center的值,而是根据origin和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后的括号中指定set方法内的形参名,也可以不指定,使用默认newValue

      注意:属性,例如view中的控件,应该用存储属性,不应该用计算属性

      lazy var loginButton: UIButton = {
          let button = UIButton()
          button.backgroundColor = UIColor.red
          return button
      }()
      
    • 只读计算属性,括号内没有setter只有getter方法,也可以省略get关键字,简写成如下,直接返回计算值:
      struct Cuboid {
          var width = 0.0, height = 0.0, depth = 0.0
          var volume: Double {
              return width * height * depth
          }
      }
      
    • 属性监视器,监测储存属性变化,用来检测存储属性(懒加载的存储属性除外)。可以为重载的计算属性添加属性监视器,不需要对无法重载的计算属性添加属性监视器。使用willSet在赋值前监测,使用didSet在赋值后监测
      class StepCounter {
          var totalSteps: Int = 0 {
              willSet(newTotalSteps) {
                  print("About to set totalSteps to \(newTotalSteps)")
              }
              didSet {
                  if totalSteps >= oldValue {
                      print("Added \(totalSteps - oldValue) steps")
                  }
              }
          }
      }
      

      注意: willSetdidSet在构造器中初始化的时候不会被调用,只有在本类构造器外的地方被设定值时才会触发。包括其子类的构造器中,设定值就可以触发。

    • 被监测的属性以inout类型作为函数参数时,willSetdidSet在函数结尾总会被调用(传入时不确定),是因为inout的拷贝原理导致的
    • 全局变量会自动延迟计算,和延迟属性类似,不过不需要使用lazy关键字,但是局部变量不会延迟计算
    • 类型属性,使用static关键字修饰类型属性。类似于C语言的静态变量和常量,应用于类、结构体、枚举。当声明了类型属性后,该类的所有实例均有共同的此属性变量值。区别于实例属性,实例属性在创建的每一个实例中都有一套不同的属性值。
      存储类型属性可以是let或者var,计算类型属性只能是var,这跟普通实例属性一致。
      struct SomeStructure {
          //使用static关键字
          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关键字表示可被子类重写
          class var overrideableComputedTypeProperty: Int {
              return 107
          }
      }
      

      类型属性必须有默认值,因为类型本身没构造器。类型属性为懒加载类型,只会执行一次,即使在多个线程中,且不需要lazy关键字。

    • 类型属性的读写使用点语法,与实例属性基本一致,区别在于作用于类型而不是实例。
      print(SomeStructure.storedTypeProperty)
      // Prints "Some value."
      SomeStructure.storedTypeProperty = "Another value."
      print(SomeStructure.storedTypeProperty)
      // Prints "Another value."
      print(SomeEnumeration.computedTypeProperty)
      // Prints "6"
      print(SomeClass.computedTypeProperty)
      // Prints "27"
      
    • 使用类型属性来描述类型的通用属性值,可以随着某一实例变化而影响这个值。例如角色最高得分,其中某一角色得到最高分的时候会刷新所有角色能看到的最高分。一个具体的例子如下:
      struct AudioChannel { 
          //定义等级上限
          static let thresholdLevel = 10
          //定义当前最高等级
          static var maxInputLevelForAllChannels = 0
          var currentLevel: Int = 0 {
              didSet {
                  //如果超过等级上限取等级上限
                  if currentLevel > AudioChannel.thresholdLevel {
                      // cap the new audio level to the threshold level
                      currentLevel = AudioChannel.thresholdLevel
                  }
                  //超过当前最高等级,刷新当前最高等级
                  if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                      // store this as the new overall maximum input level
                      AudioChannel.maxInputLevelForAllChannels = currentLevel
                  }
              }
          }
      }
      
      var leftChannel = AudioChannel()
      var rightChannel = AudioChannel()
      
      //左通道刷新最高等级为7
      leftChannel.currentLevel = 7
      print(leftChannel.currentLevel)
      // Prints "7"
      print(AudioChannel.maxInputLevelForAllChannels)
      // Prints "7"
      
      //右通道刷新最高等级为10
      rightChannel.currentLevel = 11
      print(rightChannel.currentLevel)
      // Prints "10"
      print(AudioChannel.maxInputLevelForAllChannels)
      // Prints "10"
      

    相关文章

      网友评论

          本文标题:Properties

          本文链接:https://www.haomeiwen.com/subject/lzjrpxtx.html