You can't connect the dots looking forward; you can only connect them looking backwards.
-- Steve Jobs
说一下Swift的属性。
很久没有跟人聊概念技术尤其是耳熟能详的概念,仔细一想,这属性到底是啥?
我知道你问的是啥,我也知道是啥,但我不知道你想让我说啥,尴尬了。
属性:是描述一个事物的特征?我都怀疑我还是不是不爱说话的程序员了...
比方说抽象一个Person类,定义一个Int的age就是属性。
class Person {
var age: Int
}
struct Point {
var x: Int
var y: Int
}
在Swift中,通过实例访问的属性称为实例属性,通过类名访问的属性称为类型属性。
实例属性分存储属性、计算属性。存储属性类似成员变量存储在实例的内存中;计算属性本质是方法不占用实例的内存。
存储属性
存储属性规定:在创建类、结构体的实例时,必须为所有的存储属性设置一个合适的初始值。使用lazy可以定义一个延迟存储属性,在第一次用到属性的时候才会进行初始化。
lazy属性必须是var,多线程访问不能保证只初始化一次。结构体实例需要定义为var,因为延迟属性初始化时需改变结构体内存。
计算属性
定义计算属性只能是var,不能用let。
set传入的新值默认是newValue,也可以自定义。
只有get,没有set就是只读计算属性。
类型属性也分存储类型属性、计算类型属性。存储类型属性相当于全局变量,整个程序运行过程中只有一份内存,用static修饰;计算类型属性相当于全局函数。用static/class修饰。static修饰的不能被子类重写,class修饰的可以重写。
存储类型属性
默认lazy且线程安全(调用dispatch_once_f),第一次使用时才初始化
计算类型属性
默认lazy且线程安全
class Person {
var gender: String //存储属性
//计算属性
//根据gender是男是女算出sex值,方便传给后台Bool值,设置sex时同时改变gender的值
var sex: Bool {
set {
gender = newValue ? "男" : "女"
}
get {
gender == "男"
}
}
//存储类型属性
static var count: Int = 0
//计算存储类型
static var hands: Int {
get {
count * 2
}
}
//懒加载存储属性,延迟加载
lazy var pet = Pet()
var cloth = Cloth()
init(gender: String) {
self.gender = gender
}
}
class Pet {
var name: String = "旺财"
init() {
//用到的时候初始化
print("Pet init")
}
}
class Cloth {
init() {
print("Cloth init")
}
}
属性观察器
为非lazy的var存储属性社会属性观察器,初始化器中设置属性值(设置初始值)不会触发属性观察器
var age: Int {
willSet {
print("willset", newValue)
}
didSet {
print("didset", oldValue, radius)
}
}
重写属性
存储属性、计算属性重写为计算属性,只能重写var属性,子类重写后的属性的权限不能小于父类的。被final修饰的属性禁止被重写。
可以在子类中为父类属性增加属性观察器(只读、let除外)
存储属性没有属性观察器的增加属性观察器,有属性观察器的调用顺序子类的willSet->父willSet->父didSet->子类的didSet
计算属性先要获取oldValue,所以顺序是get->sub willSet->set->get->sub didSet
class Person {
class var age: Int {
set {
print("set", newValue)
}
get {
print("get")
return 18
}
}
}
class Student: Person {
override static var age: Int {
willSet {
print("Sub willset", newValue)
}
didSet {
print("Subdidset", oldValue, age)
}
}
}
var s = Student()
Student.age = 19
/*
get
Sub willset 19
set 19
get
Subdidset 18 18
*/