- 属性是将值跟特定的类、结构体或者枚举关联。存储属性存储常量或者变量作为实例的一部分,用于类和结构体;计算属性是用来计算一个值,可以用在类、结构体和枚举。
- 存储属性和计算属性通常与特定的类型的实例关联。但是,属性也可以直接作用于类型本身,这样的属性成为类型属性。
- Swift可以定义属性观察器来监控属性值的改变,属性观察期可以添加到自己定义的存储属性上,也可以添加到父类继承的属性上
1.存储属性
- 存储属性就是存储在特定类、结构体里的一个常量或者变量。
- 可以在定义存储属性的时候指定默认值。
- 可以在构造过程中设置或者修改存储属性的值。
// 定义一个结构体如下,FixedLengthRange代表一个创建后无法改变的区间
struct FixedLengthRange {
var firstValue: Int
let lenght: Int
}
var rangeOfThreeItens = FixedLengthRange(firstValue: 0, lenght: 3)
// rangeOfThreeItens 实例包括了名为firstValue的变量存储属性和lenght的常量存储属性
// 其中lenght在创建后无法被修改
rangeOfThreeItens.firstValue = 7;
// rangeOfThreeItens 现在的表示7 8 9的区间
1.1 常量结构体的存储属性
- 当创建了一个结构体的实例并赋值一个常量,那么无法修改该实例的任何属性。
- 结构体是值类型,当值类型的实例被声明为常量的时候,它的所有属性都变成了常量。
当尝试下面的修改时,就会报错
let rangeOfThreeItens = FixedLengthRange(firstValue: 0, lenght: 3)
rangeOfThreeItens.firstValue = 8
1.2延迟存储属性
- 延迟存储属性是指第一次被调用的时候才会计算其初始值的属性,就是常说的懒加载。
- Swift在属性前加lazy关键字来标记一个延迟存储属性,延迟存储属性必须用变量(var关键字)。
- 当属性依赖其他外部因素影响(如构造过程,初始值复杂,大量计算),适合用延迟属性。
// DataImporter是一个导入数据的类,导入过程会消耗大量的时间
class DataImporter {
var fileName = "data.text"
/** 导入数据 **/
}
// DataManager用来管理和提供对这个字符串数组的访问
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
/** 管理数据 **/
}
let manager = DataManager()
manager.data.append("someData")
manager.data.append("someMore")
简单描述了一个DataManager类,导入文件的过程。DataManager用来管理数据的导入,依赖与DataImporter的功能。导入数据消耗太多的时间,而且DataManager也可能不导入数据就完成了管理数据的过程。DataImporter不需要立刻创建,只有在使用的时候才去创建。
print(manager.importer.fileName)
只有执行上述代码的时候,DataImporter实例才会被创建。
1.3存储属性和实例变量
- OC中,提供了为类实例存储值和引用提供了两种方法,通过_XXXXX或者self.XXXXX.
- Swift统一了OC的方法,属性没有对应的实例变量(_XXXXX)
- 一个类型中属性的全部信息--命名、类型、内存管理特性,全部都在唯一的地方(类型定义中)
2.计算属性
- 枚举、类、结构体除了拥有存储属性,还可以定义计算属性。
- 计算属性不直接存储值,而是提供一个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 * 0.5)
let centerY = origin.y + (size.height * 0.5)
return Point(x: centerX, y: centerY)
}
set(newCenter){
origin.x = newCenter.x - (size.width * 0.5)
origin.y = newCenter.y - (size.height * 0.5)
}
}
}
// 创建一个矩形
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: 20.0, y: 20.0)
2.1便捷setter声明
- 如果计算属性的setter没有定义表示新值的参数名,则可以用默认值newValue,上述代码可以改写
struct Rect {
var origin = Point()
var size = Size()
var center: Point{
get{
let centerX = origin.x + (size.width * 0.5)
let centerY = origin.y + (size.height * 0.5)
return Point(x: centerX, y: centerY)
}
set{
origin.x = newValue.x - (size.width * 0.5)
origin.y = newValue.y - (size.height * 0.5)
}
}
}
2.2只读计算属性
- 只有getter没有setter的计算属性
- 只读计算属性总是返回一个值,可以通过点语法访问,但是不能设置
- 只读计算属性可以省略get和花括号
// 一个结构体 ,volume计算体积
struct Cuboid{
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double{
return width * height * depth
}
}
let newCuboid = Cuboid(width: 3.0, height: 4.0, depth: 5.0)
3.属性观察器
- 属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用。
- 延迟属性不可以设置属性观察器
- 可以通过重写属性的方式为继承的属性添加观察器
- willSet : 在新的值被设置之前调用
- didSet : 在新的值被设置之后调用
- 父类的属性在子类的构造器被赋值时,观察器同样会被触发
// StepCounter是一个计步器
class StepCounter{
var totalStep: Int = 0{
willSet(newTotalSteps){
print("现在总步数是\(newTotalSteps)步")
}
didSet{
if totalStep > oldValue{
print("增加了\(totalStep - oldValue)步")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalStep = 200;
// 现在总步数是200,增加了200步
stepCounter.totalStep = 500;
// 现在总步数是500,增加了300步
4.全局变量和局部变量
全局变量是在函数、方法、闭包或者其他类型之外定义的变量。局部变量是在函数、方法、或者闭包内定义的。
- 计算属性和属性观察器所描述的模式也可以用于全局变量和局部变量。
- 默认的全局和局部变量都是存储型变量,跟存储属性类似,它提供存储空间,并且允许读取和写入
- 全局和局部变量都可以定义计算属性和添加属性观察器。
- 注意!!
- 全局的常量或者变量都是延迟计算的,跟延迟存储属性不同的地方在于,全局的常量或者变量不需要标记lazy。
- 局部范围的常量或者变量不会延迟计算。
5.类型属性
实例的属性属于一个特定的实例,实例之间的属性相互独立,也可以为类型本身设置属性,不管类有多少的实例,这些属性只有唯一一份,这个就是类型属性。
- 类型属性,比如所有实例都有一个常量(类似C语言的静态常量),或者拥有一个变量(类似C语言的动态变量)。
- 值类型的存储类型属性可以是变量或者常量,计算型属性跟计算属性一样只能定义成常量属性。
- 注意!!
- 必须给存储型类型属性,指定一个默认值,因为类型本身,无法在初始化过程中,使用构造器给类型属性赋值、
- 存储型类型属性是延迟初始化的,并且不要加lazy,多线程同时访问也只会初始化一次。
5.1类型属性语法
在Swift中,类型属性是类型定义的一部分,写在类型最外层花括号内,作用域就是在该类型支持的范围内。
- 用关键字static来定义类型属性
- 在类中,用关键字class来支持子类对父类的实现进行重写。
// 只写了只读计算型类型属性
struct MyStruct{
static var storedTypeProperty = "Some Value"
static var comutedTypeProperty : Int{
return 998
}
}
enum MyEnum{
static var storedTypeProperty = "Some Value"
static var comutedTypeProperty : Int{
return 998
}
}
class MyClass {
static var storedTypeProperty = "Some Value"
static var comutedTypeProperty : Int{
return 998
}
class var overridedableComutedTypeProperty : Int{
return 100
}
}
5.2获取和设置类型属性的值
跟实例的属性一样,类型属性可以用点语法来访问,只是不需要通过实例。
网友评论