Swift开篇008->属性

原创 2016年06月01日 11:04:29

PART_A 属性简介

  • 存储属性:存储常量(let)或变量(var),作为实例的一部分. 只能作用于类和结构体

  • 计算属性:计算一个值. 可用于类、结构体、枚举. 必须用 var 声明

  • 类型属性:上述两属性通常与特定类型的实例关联. 该属性可直接作用于类型本身


PART_B 存储属性

  1. 案例

    struct Range {
        var startIndex: Int // 变量存储属性
        let width: Int // 常量存储属性(创建实例时被初始化)
    }
    
    var range = Range(startIndex: 0, width: 5)
    // 区间为 0...5
    range.startIndex = 3
    // 区间为 3...8
  2. 常量结构体的存储属性

    • 当值类型的实例被声明为常量时,其所有属性也成常量

    • 当引用类型的实例被声明为常量后,仍可修改该实例的变量属性

      let rangeFix = Range(startIndex: 3, width: 8)
      rangeFix.startIndex = 1
      // 报错. 因结构体是值类型,而值类型的实例被声明为常量,其属性均成常量
  3. 延迟存储属性:lazy var声明. 第一次被调用时才计算其属性的初始化值

    • 使用场景

      • 当属性的值依赖于在实例的构造过程结束后才会知道具体值的外部因素时

      • 当获得属性的初始值需要复杂或大量计算时

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

      class DataProvider {
          // 导入文件(耗时操作)
          var fileName = "data.txt"
      }
      
      class DataManager {
          lazy var provider = DataProvider()
      
          // 数据管理
          var data = [String]()
      }
      
      let manager = DataManager()
      manager.data.append("Some data")
      manager.data.append("Some more data")
      // DataProvider 实例还没有被创建
      
      
      print(manager.importer.fileName)
      // DataProvider 实例被创建(此时第一次被调用)
  4. 存储属性和实例变量

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

PART_C 计算属性(-案例值得琢磨-)

  1. 不直接存储值,提供 gettersetter 来间接获取和设置值

    // 定义中心坐标
    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 {
            // getter:返回 Point 实例(中心)
            get {
                let centerX = origin.x + (size.width / 2)
                let centerY = origin.y + (size.height / 2)
                return Point(x: centerX, y: centerY)
            }
    
            // setter:设置 Point 中心坐标
            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 squareCenter = square.center
    // 中心坐标 (5, 5)
    
    square.center = Point(x: 15.0, y: 15.0)
    
    print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
    // 输出 "square.origin is now at (10.0, 10.0)”
  2. 便捷 setter 声明

    • 若计算属性的 setter 没有定义新值的参数名,则可使用默认名称 newValue

      // 上述代码的 setter 可简写
      set {
          origin.x = newCenter.x - (size.width / 2)
          origin.y = newCenter.y - (size.height / 2)
      }
  3. 只读计算属性:只有 getter 没有 setter 的计算属性,总是返回一个值

    struct Cuboid {
        var width = 0.0, height = 0.0, depth = 0.0
    
        // 只读计算属性
        var volume: Double {
            return width * height * depth
        }
    }
    
    let rect1 = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
    print("the volume of rect1 is \(rect1.volume)")

PART_D 属性观察器

  • 可为除延迟存储属性外的其他存储属性添加

  • 可通过重写属性的方式为继承的属性(存储属性、计算属性)添加

  • 父类的属性在子类构造器中被赋值时,其在父类的观察器会被调用

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

    • willSet:新值被设置前调用

    • didSet:新值被设置后调用

      class StepCounter {
          var totalSetps: Int = 0 {
              // newTotalSteps:新值(默认 newValue)
              willSet(newTotalSteps) {
                  print(newTotalSteps)
              } didSet {
                  // oldValue:旧值 
                  if totalSetps > oldValue {
                      print(totalSetps - oldValue)
                  }
              }
          }
      }
      
      let stepCounter = StepCounter()
      stepCounter.totalSetps = 50
      // 50
      // 50
      
      stepCounter.totalSetps = 90
      // 90
      // 40
      
      stepCounter.totalSetps = 80
      // 80
  • 若一个属性的 didSet 观察器里赋值,该值会替代之前设置的值


PATR_E 全局变量和局部变量

  1. 定义

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

    • 局部变量:在函数、方法或闭包内部定义的变量

  2. 注意

    • 全局的常量或变量都是延迟计算的(省略 lazy 修饰符)

    • 局部的常量或变量从不延迟计算

  3. 计算属性和属性观察器所描述的功能可用于全局变量和局部变量


PART_F 类型属性(static):定义某个类型所有实例共享的数据

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

  • 必须给存储型类型属性指定默认值(无构造器,无法初始化时赋值)

  • 存储型类型属性是延迟初始化的(省略 lazy). 即使它们被多个线程同时访问,系统也保证只会对其进行一次初始化


  1. 语法

    struct SomeStructure {
        // 存储型类型属性
        static var storedTypeProperty = "Some value."
        // 计算型类型属性(本例所用是只读的)
        static var computedTypeProperty: Int {
            return 5
        }
    }
    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 7
        }
    
        // 为类定义计算型类型属性时,改用 class 支持子类对父类的实现进行重写
        class var overrideableComputedTypeProperty: Int {
            return 8
        }
    }
  2. 获取和设置类型属性的值

    • 和实例属性一样通过 .,但类型属性是通过类型本身来访问(是不是很像JAVA的静态类)

      SomeStructure.storedTypeProperty = "Another value."

  3. 案例:两个喇叭的音量

    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 // 左声道音量为 7
    rightChannel.currentLevel = 11 // 右声道音量为 10(控制在音量上限内)

以上。如有错误和疑问,欢迎指正提出。 catface.wyh@gmail.com

版权声明:本文为博主原创文章,如需转载请声明作者信息,谢谢。

008--swift基础语法(数组)

数组的定义 //MARK: -数组的定义 func demo1() { //OC使用[]定义数组,Swift一样,但是没有`@` //自动推导的结果是[St...

swift基本语法(总结提炼版)之008 swift 之字典

字典 /// 定义并实例化字典 var dict = [String: AnyObject]() dict["name"] = "zhangsan" dict["age"] = 18 print...

Swift开篇009->方法

**PART_A 实例方法** 1. **简介** - **实例方法:可属于某个特定类、结构体或枚举实例的方法** - **实例方法能隐式访问它所属类型的所有其他实例方法和属性** ...

Swift开篇005->闭包

重点内容 以上。如有错误和疑问,欢迎指正提出。 catface.wyh@gmail.com

幻方解法之swift语言程序实现开篇

/* 程序思想参考百度百科上"幻方法则" 2015-01-27 http://baike.baidu.com/link?url=7ynfkLYfGv4f7PtQkuH4PSn_8IFr_QFAN-...
  • swibyn
  • swibyn
  • 2015年01月29日 15:36
  • 394

Swift开篇007->类和结构体

PART_A 类&结构体对比 共同点定义属性:存储值 定义方法:提供功能 定义附属脚本:访问值 定义构造器:生成初始化值 通过扩展增加默认实现的功能 实现协议以提供某种标准功能 类的附加功能继承允...

Swift开篇012->构造过程

一、构造过程的简介 构造过程是使用类、结构体或枚举类型的实例之前的准备过程. 在新实例可用前必须执行这个过程,具体操作包括设置实例中每个存储型属性的初始值和执行其他必须的设置或初始化工作 通过定义...

Swift开篇010->下标

1. **简介** - **下标可定义在类、结构体、枚举中,是访问集合、列表、序列元素的快捷方式** 2. **语法格式** - **下标了设定为读写或只读** ``` //...

Swift开篇013->析构过程

析构器只适用于类类型,当一个类的实例被释放之前,析构器会被立即调用. 析构器用关键字 deinit 来标示,类似于构造器要用 init 来标示 一、析构过程原理Swift 会自动释放不再需要的实例以释...

Swift开篇003->控制流、函数

PART_A 控制流 forfor ... infor index in 1 ... 5 { print(index) }let names = ["cat", "dog", "fish"]...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Swift开篇008->属性
举报原因:
原因补充:

(最多只允许输入30个字)