属性
程序员文章站
2022-03-01 21:17:57
...
- 属性有存储属性,计算属性
- 存储属性包括常量存储属性,变量存储属性
- 常量存储属性特性
- 如果一个值类型变量被声明为let,那么这个变量下的所有都是常量不可以改。
- 如果是一个引用类型被定义为let,那么这个类型下的常量不可改变,变量依然可以改变。
struct Size {
var a = 0
}
class React {
var area = 0.0
}
let size = Size(a: 4)
size.a = 2
let react = React()
react.area = 3
react.area = 5
- 延时存储属性
- 当一个属性加载大量数据,并且它可能用到,也可能用不到,这时候推荐使用延时存储属性
- 延时存储属性一定是var类型
class DataImport {
var fileName = "file.txt"
}
class DataManger {
lazy var importer = DataImport()
var data = [String?]()
}
let dataManager = DataManger()
dataManager.data.append("one.txt")
dataManager.data.append("two.txt")
print(dataManager.importer.fileName)
- swift属性没有实例变量,它的变量就是属性。
- 计算属性
- 如果这个属性是靠其他属性计算得来的,那么这个属性应该用计算属性。
- 计算属性要用var类型和延时存储属性一样都用var。
- 之后写好计算属性名字后边要写上类型,之后大括号。
- 必须要有一个get方法,用来返回这个计算属性的计算结果。
- 可以有一个可选的set方法,该方法内部可以用newValue来省略参数。
- 在用构造器初始化属性时候,其实是在初始化存储属性,计算属性不用初始化,因为他可以用存储属性计算得来。
- 在使用时候只要给相关的存储属性赋值后,计算属性就可以计算得来。
- 在使用时候只要给计算属性赋值了,那么就可以得出新的存储属性.
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct React {
var origin = Point()
var size = Size()
var center: Point {
get{
let x = origin.x + (size.width/2.0)
let y = origin.y + (size.height/2.0)
return Point(x: x, y: y)
}
set{
origin.x = newValue.x - (size.width/2.0)
origin.y = newValue.y - (size.height/2.0)
}
}
}
var react = React(origin: Point(x: 0.0, y: 0.0), size: Size(width: 20, height: 10))
print(react.center)
react.center = Point(x: 30, y: 40)
print(react.origin)
- 只读计算属性
- 首先该属性是用其他存储属性计算得到的,确定该属性是计算属性。
- var name:type{}
- 确定该计算属性有没有setter方法
- 如果没有setter方法,那就是只读计算属性,这时候可以直接省略get关键字。
- 如果有seeter方法,那就是可读写计算属性,get关键字不可以省略,set可以省略参数。
struct Cuboid {
var width = 0.0, height = 0.9, depth = 0.0
var volume: Double {
return width * height * depth
}
}
var cuboid = Cuboid(width: 10, height: 10, depth: 5)
print("volume: \(cuboid.volume)")
cuboid.width = 20
print("volume: \(cuboid.volume)")
- 属性观察器
- 如果要观察计算属性的赋值变化就添加set方法。
- 如果要观察存储属性的赋值变化可以用属性观察器。
- 所以一般属性观察器用在存储属性上。
- willSet可以取到newValue,didSet可以取到oldValue
class StepCounter {
var totalStep = 0 {
willSet{
print("willSet --- 新值:\(newValue) 旧值:\(totalStep)")
}
didSet{
print("didSet --- 新值:\(totalStep) 旧值:\(oldValue)")
}
}
}
var step = StepCounter()
step.totalStep = 100
step.totalStep = 300
step.totalStep = 800
//打印如下
//willSet --- 新值:100 旧值:0
//didSet --- 新值:100 旧值:0
//willSet --- 新值:300 旧值:100
//didSet --- 新值:300 旧值:100
//willSet --- 新值:800 旧值:300
//didSet --- 新值:800 旧值:300
- 属性观察器变量如果传入一个inout类型函数的参数中,即使函数内部没有操作。也会触发属性观察器。
class StepCounter {
var totalStep = 0 {
willSet{
print("willSet --- 新值:\(newValue) 旧值:\(totalStep)")
}
didSet{
print("didSet --- 新值:\(totalStep) 旧值:\(oldValue)")
}
}
}
var step = StepCounter()
func test(a: inout Int){
}
test(a: &step.totalStep)
- 全局变量和局部变量
- 全局变量都是延时变量,用到时候才会加载。
- 局部变量一定不是延时变量,也不允许写lazy关键字。
- 类外就是全局变量。类内是属性,方法闭包内部是局部变量。
//全局变量
var globleVar = 4.5
class Test {
//属性
var a = 1
init() {
//局部变量
var b = 2
}
}
- 类型属性
- 如果一个属性被所有实例对象共享那就考虑用类型属性
- 类型属性关键字是static,它是用类访问的变量。和类有关
- 实例属性是实例访问的属性,和实例有关
struct AudioChannel {
static let thresholdLevel = 10
static var maxLevelForAllChannel = 0
var curLevel = 0{
didSet{
if curLevel > AudioChannel.thresholdLevel {
curLevel = AudioChannel.thresholdLevel
}
if curLevel > AudioChannel.maxLevelForAllChannel {
AudioChannel.maxLevelForAllChannel = curLevel
}
}
}
}
var leftAudioChannel = AudioChannel(curLevel: 0)
var rightAudioChannel = AudioChannel(curLevel: 0)
leftAudioChannel.curLevel = 2
print(AudioChannel.maxLevelForAllChannel)
rightAudioChannel.curLevel = 3
print(AudioChannel.maxLevelForAllChannel)
rightAudioChannel.curLevel = 13
print(AudioChannel.maxLevelForAllChannel)
- 总结
- 类外是全局变量 - 延时加载
- 类内是属性
- 属性包括实例属性和类型属性
- 存储属性
- 常量存储属性
- 变量存储属性
- 延时存储属性
- 属性观察器
- 计算属性
- 存储属性
- 属性包括实例属性和类型属性
- 函数闭包内部是局部变量 - 一定不是延时加载的,也不允许用lazy关键字