一: 存储属性
非 lazy 型的属性,必须在自己的 init 完成之前,完成初始化。
1、直接赋值:
let attr: Int = 1
2、用自执行的 closure 赋值
// 当初始化工作有多个属性要设置的时候,用 closure 更合适
let attr: Int = {
let x = 1 + 2
return x
}()
// 上边等同于 先定义,然后在 init 中赋值 see: https://stackoverflow.com/questions/35065649/are-computed-properties-evaluated-every-time-they-are-accessed
let attr: Int
init() {
self.attr = 1
super.init()
}
总之,存储属性,要求在 init 之前完成赋值,除非是可选类型。可空类型,可以不必赋值
var op: Int?
3、lazy 型
第一次访问时创建:
private(set) lazy var imageView: UIImageView = {
let view = UIImageView()
view.contentMode = .scaleAspectFit
view.backgroundColor = .clear
return view
}()
4、willSet didSet 监听属性值得变化
调用的时候,先子类,后父类.
class Test {
var property1: String = "aaa" {
// 设置值之前监听,参数为新值
willSet {
// 默认参数名 newValue
print("Test property will set: \(newValue)")
}
didSet {
// 默认参数名是 oldValue
print("Test property will set: \(oldValue)")
}
}
}
class SubTest: Test {
override var property1: String {
willSet {
print("SubTest property will set")
}
}
}
let subTest = SubTest()
subTest.property1 = "bbb"
// output:
// SubTest property will set
// Test property will set
二: 计算属性
本身就有个 set get, 因此不需要 willSet/didSet。计算属性,事实上是一个 closure,在语法上 计算属性只通过声明式的语法进行定义,这也区别于了存储属性。
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()
// 计算属性 center ,注意语法上没有用 = 进行赋值,而只是用声明的语法格式
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)
}
}
}
三、在 extension 中增加存储属性
默认 swift extension 支持计算属性,但不支持存储属性,可以用类似 oc 的方式,进行绑定。Swift 4 之后,可以用内部 struct 结合计算属性实现。不过这种方式有个致命的问题,因为 struct 中用的是 static 变量,静态属性,不管多少个实例都是同一个值。
extension ExtClass: OriginalClass {
struct Dragger {
static var offset: Double = 0.0
static var startX: Double = 0.0
}
var draggingOffset: Double {
get {
return Dragger.offset
}
set {
Dragger.offset = newValue
}
}
}