专注收集记录技术开发学习笔记、技术难点、解决方案
网站信息搜索 >> 请输入关键词:
您当前的位置: 首页 > Swift

从 Playgrounds 论 Swift(十): 属性(Properties)

发布时间:2011-06-30 07:29:15 文章来源:www.iduyao.cn 采编人员:星星草
从 Playgrounds 论 Swift(10): 属性(Properties)
转载请声明出处:http://blog.csdn.net/jinnchang/article/details/43315349

1、概念

属性将值跟特定的类、结构或枚举关联。

2、存储属性

存储属性就是存储在特定类或结构体的实例里的一个变量或常量。
(1)存储属性的使用

// 定义一个结构体,变量存储属性 width 和常量存储属性 height
struct Resolution {
    var width : Int
    let height : Int
}
var oneResolution = Resolution(width: 0, height: 768)
oneResolution.width = 1024
let twoResolution = Resolution(width: 0, height: 768)
// twoResolution.width = 1024
// 编译出错,因为 twoResolution 声明成了常量,而且 struct 是值类型

// 定义一个类,变量存储属性 age 和常量存储属性 name
class Teenager {
    var name : String = ""
    var age : Int = 18
}
var oneTeenager = Teenager()
oneTeenager.name = "Tom"
let twoTeenager = Teenager()
twoTeenager.name = "Jack"
// 虽然 twoTeenager 被声明成了常量,但是上述语句编译正确
上述例子中分别讲述了存储属性(变量与常量)的用法,在 struct 和 class 表现出来的现象不同是因为 struct 是值类型,class 是引用类型。
(2)延迟存储属性
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。
在属性声明前使用 lazy 关键字来标识一个延迟存储属性。延迟属性很有用,当属性的值依赖于在实例构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。
注意:延迟存储属性必须声明成变量。因为属性的值在实例构造完成之前可能无法得到,而常量属性在构造过程完成之前必须要有初始值。

// 定义一个将外部文件中的数据导入的类
class DataImporter {    
    var fileName = "data.txt"
    // 此处提供数据导入功能
}

// 定义一个管理数据的类
class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
    // 此处提供数据管理功能
}

// 实例化 manager 时未创建 importer 属性
let manager = DataManager()
manager.data.append("Some data")
// 被访问时创建 importer 属性
println(manager.importer.fileName)
DataManager 的一个功能是从文件导入数据,该功能由 DataImporter 类提供。DataImporter 需要消耗不少时间完成初始化,因为它的实例在初始化时可能要打开文件,还要读取文件内容到内存。DataManager 也可能不从文件中导入数据。所以当 DataManager 的实例被创建时,没必要创建一个 DataImporter 的实例,更明智的做法是当用到 DataImporter 的时候才去创建它。

3、计算属性

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

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}

// 定义一个 Rect 结构体,包含一个计算属性 center
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))
square.center = Point(x: 15.0, y: 15.0)
println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// prints "square.origin is now at (10.0, 10.0)"
注意:如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称 newValue。
(2)只读计算属性
只有 getter 没有 setter 的计算属性就是只读计算属性。
只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。
注意:必须使用 var 关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。

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)")
// prints "the volume of fourByFiveByTwo is 40.0"

4、属性观察器

属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。
属性观察器有以下两种,可选择性添加:
  • willSet : 在设置新的值之前调用。
  • didSet : 在新的值被设置之后立即调用。
willSet 观察器会将新的属性值作为固定参数传入,在 willSet 的实现代码中可以为这个参数指定一个名称,或者使用默认名称 newValue 表示。
didSet 观察器会将旧的属性值作为固定参数传入,在 didSet 的实现代码中可以为这个参数指定一个名称,或者使用默认名称 oldValue 表示。
注意:willSet 和 didSet 观察器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时调用。

class StepCounter {
    var totalSteps: Int = 0 {
        willSet(newTotalSteps) {// 这里使用了自定义参数名
            println("About to set totalSteps to \(newTotalSteps)")
        }
        didSet {// 此处未使用自定义参数名,所以使用默认参数名 oldValue
            if totalSteps > oldValue  {
                println("Added \(totalSteps - oldValue) steps")
            }
        }
    }
}

let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 100
// About to set totalSteps to 100
上述例子中为 willSet 观察器自定义了参数名 newTotalSteps,所以内部调用时使用 newTotalSteps。而 didSet 并没有自定义参数名,所以调用时使用默认参数名 oldValue。
如果在 didSet 观察器里为属性赋值,这个值会替换观察器之前设置的值,而且不会触发 willSet 和 didSet。

5、类型属性

类型属性:为类型本身定义的属性,不管类型有多少个实例,这些属性都只有唯一一份。
使用关键字 static 来定义值类型的类型属性,关键字 class 来为定义类(class)的类型属性。
对于值类型(指结构体和枚举)可以定义存储型和计算型类型属性,对于类(class)则只能定义计算型类型属性。

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return  countElements(storedTypeProperty)
    }
}

enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return countElements(storedTypeProperty)
    }
}

class SomeClass {
    class var computedTypeProperty: Int {
        return 100
    }
}

println(SomeStructure.storedTypeProperty)           // Some value.
println(SomeStructure.computedTypeProperty)         // 11
println(SomeEnumeration.storedTypeProperty)         // Some value.
println(SomeEnumeration.computedTypeProperty)       // 11
println(SomeClass.computedTypeProperty)             // 100
上述例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。

6、结语

文章最后更新时间:2015年1月31日19:37:08。
欲了解更细致的请参考官方文档:Properties
友情提示:
信息收集于互联网,如果您发现错误或造成侵权,请及时通知本站更正或删除,具体联系方式见页面底部联系我们,谢谢。

其他相似内容:

热门推荐: