《Swift从入门到精通》(七):属性
属性(学习笔记)
环境Xcode 11.0 beta4 swift 5.1
-
属性(Properties)
- 属性是把值和特定的类、结构体、枚举关联在一起
- 属性主要是分为存储属性(Stored Properties)和计算属性(Computed Properties)
- 存储属性是用来存储实例的常量或者变量
- 计算属性主要是用来计算值
- 计算属性可以定义在类、结构体、枚举
- 存储属性可以定义在类、结构体
-
存储属性(Stored Properties)
-
可以用
var
、let
修饰,后者一旦初始化就不可更改struct FixedLengthRange { var firstValue: Int let length: Int } var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // the range represents integer values 0, 1, and 2 rangeOfThreeItems.firstValue = 6 // the range now represents integer values 6, 7, and 8
-
结构体实例常量的存储属性,即被
let
修饰,此时的存储属性被var
修饰了不能更改,因为结构体是值类型,结构体变量的存储属性的内存是存储在结构体变量的内存中的let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) // this range represents integer values 0, 1, 2, and 3 rangeOfFourItems.firstValue = 6 // this will report an error, even though firstValue is a variable property
-
延迟存储属性(Lazy Stored Properties),用
lazy
来标识且只能申明为var
,延迟存储属性是第一用到才赋值,而let
修饰的属性要在初始化前就要有值// 以下示例代码类不是完整的类 class DataImporter { /* DataImporter is a class to import data from an external file. The class is assumed to take a nontrivial amount of time to initialize. */ var filename = "data.txt" // the DataImporter class would provide data importing functionality here } class DataManager { lazy var importer = DataImporter() var data = [String]() // the DataManager class would provide data management functionality here } let manager = DataManager() manager.data.append("Some data") manager.data.append("Some more data") // the DataImporter instance for the importer property has not yet been created print(manager.importer.filename) // the DataImporter instance for the importer property has now been created // Prints "data.txt"
-
存储属性&实例变量,在OC中有两种方式存储值和类的实例对象,即属性和实例变量(即成员变量);Swift统一了这些概念,属性的所有信息(包括它的名称、类型和内存管理特性)都在类型定义的时候,作为类型的一部分定义在类型中
-
-
计算属性(Computed Properties)
-
计算属性不是真的用来存储值,而是提供
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) } } } 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) print("square.origin is now at (\(square.origin.x), \(square.origin.y))") // Prints "square.origin is now at (10.0, 10.0)"
-
简写的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声明(隐式返回即省略
return
)struct CompactRect { var origin = Point() var size = Size() var center: Point { get { Point(x: origin.x + (size.width / 2), y: origin.y + (size.height / 2)) } set { origin.x = newValue.x - (size.width / 2) origin.y = newValue.y - (size.height / 2) } } }
-
只读计算属性(Read-Only Computed Properties),只有
getter
,没有setter
,可以用var
修饰,getter
也可以省略不写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) print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") // Prints "the volume of fourByFiveByTwo is 40.0"
-
-
属性观察器(Property Observers)
-
观察和响应属性值的变化,即使设置的是相同的值也会触发;
-
可以为任意的属性添加属性观察器,延迟存储属性除外
-
可以在子类为任意继承属性(存储或计算属性)添加属性观察器
-
非重写的计算属性不需要定义属性观察器,可以在setter中观察和响应
-
可以在属性上添加
willSet
(在值存储前调用,自带一个常量参数newValue
)didSet
(新设置的值存储立即调用,自带一个常量参数oldValue
)class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { // 不用默认的newValue,自定义一个参数 print("About to set totalSteps to \(newTotalSteps)") } didSet { if totalSteps > oldValue { print("Added \(totalSteps - oldValue) steps") } } } } let stepCounter = StepCounter() stepCounter.totalSteps = 200 // About to set totalSteps to 200 // Added 200 steps stepCounter.totalSteps = 360 // About to set totalSteps to 360 // Added 160 steps stepCounter.totalSteps = 896 // About to set totalSteps to 896 // Added 536 steps
-
传递一个属性给一个
in-out
参数,willSet
didSet
都会被调用,这是因为in-out
参数的copy-in copy-out
内存管理,在函数调用的最后总是会将值写加给属性
-
-
全局和局部变量(Global and Local Variables)
- 全局和局部变量都可以设置计算属性和属性观察器
- 全局常量和变量总是延迟计算,类似延迟存储属性,但不需要
lazy
修饰 - 局部常量和变量从不是延迟计算的
-
类型属性(Type Properties)
-
是线程安全的
-
计算类型属性总是变量(同计算实例属性)和存储类型属性可以是变量或常量
-
用
static
关键字修饰,由class
定义的类可以用class
关键字标识类型属性,以便子类重写struct SomeStructure { 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 var overrideableComputedTypeProperty: Int { return 107 } } // 以上示例代码是定义成只读属性,也可以定义成可读可写属性
-