1、Swift入门学习笔记(第一版),对Swift的基础知识点进行梳理总结。知识点一直在变,只是作为参考,以苹果官方文档为准~
2、在学习完基本的知识点以后会结合官方文档及相关资料,在此版本的基础上进行添加更改。
十一、属性
1、存储属性
存储在特定类或结构体的实例里地一个变量或常量
struct Rectangle {
var length:Int
let width:Int
}
var rectangleA = Rectangle(length: 2,width: 18)
rectangleA.length = 3 //可修改,但是width不可修改
//let rectangleB = Rectangle(length: 19,width: 2)
//rectangleB.length = 2 //虽然结构体中length是变量属性,但是此处结构体的实例赋值给一个常量,则无法修改该实例的任何属性
原因:
结构体是值类型,值类型的实例被声明为常量时,其所有的属性也就变成了常量
区别于引用类型的类,把一个引用类型的实例赋给一个常量后,仍然可以修改该实例的变量属性
2、延迟存储属性
2.1、说明
用lazy
关键字声明,但是必须是变量,因为变量属性的初始值可以再实例构造完成之后才会得到。
常量不可以,因为常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
2.2、使用场景
a、属性的值依赖于在实例构造过程后才会知道具体值
b、获得属性的初始值需要复杂或大量计算时
2.3、注意点
标记为lazy属性在没有初始化时就同时被多个线程访问,则无法保证该属性只会被初始化一次
3、计算属性
不直接存储值,提供一个getter和一个可选的setter,来间接获取和设置其他属性或变量的值
必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的
3.1、实例:一矩形长度固定,宽可变
struct Rectangle {
let length:Double = 10.0
var width :Double
var square:Double {
get {
return length * width
}
set(newSquare) {
width = newSquare/length
}
//便捷的setter声明,没有定义新值得参数名,使用默认名称newValue
// set {
// width = newValue/length
// }
}
}
var rectangle = Rectangle(width: 2.0)
print("rectangle Square:\(rectangle.square),length:\(rectangle.length),width:\(rectangle.width)")
rectangle.square = 100.0
//设置属性square会调用square的setter方法来修改width属性
print("rectangle Square:\(rectangle.square),width:\(rectangle.width)")
Output:
rectangle Square:20.0,length:10.0,width:2.0
rectangle Square:100.0,width:10.0
3.2、便捷setter声明
与上面同,只是如果setter没有定义新值得参数名,那么可以使用默认名称newValue
在前面的代码中的setter备注部分
3.3、只读计算属性
只有getter没有setter的计算属性为计算属性,虽然只读但是仍要用var关键字,因为值不固定
get关键字和setter部分全部去除
4、属性观察器
a、监控和相应属性值的变化,属性被设置都会调用,包括新值和旧值相同的情况
b、可以为延迟属性外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。(不需要为非重写的计算属性添加属性观察器,其可通过setter方法直接监控和响应变化)
c、为属性添加如下一个或全部观察器
willSet
:新值被设置之前调用,指定新的常量名称传入新的属性值,不指定默认
didSet
:被设置之后立即调用,指定新的参数名称传入旧的属性值,不指定默认oldValue
d、父类属性在子类的构造器中被赋值时,父类中的willSet
和didSet
观察器会被调用
e、如果在一个属性的didSet观察器里为它赋值,这个值会替换之前的值
class Figure {
var weight:Double = 0.0{
willSet(newWeight) {
print("Weight:\(newWeight)")
}
didSet {
if weight > oldValue {
print("Amazing!You are fatter!")
}else if weight == oldValue {
print("Oh~There is nothing chang.")
}else {
weight = 0
print("So sad!You get thinner!T^T")
}
}
}
}
let myFigure = Figure()
myFigure.weight = 55.0
myFigure.weight = 60.2
myFigure.weight = 58.8
print(myFigure.weight) //结果是0,因为变瘦后,我属性里设置值为0(验证点e)
Output:
Weight:55.0
Amazing!You are fatter!
Weight:60.2
Amazing!You are fatter!
Weight:58.8
So sad!You get thinner!T^T
0.0
5、全局变量和局部变量
b、全局变量或常量都是延迟计算的,跟延迟存储属性相似,不同的是全局变量或常量不需要标记lazy特性
c、局部范围的常量或变量不会延迟计算
6、类型属性
类型属性是类型本身特有,不管有多少实例,这些属性都只有唯一一份。用于定义特定类型所有实例共享的数据
必须指定默认值,延迟初始化
6.1、语法
类型属性作为类型定义的一部分写在类型最外层的花括号内,其作用范围在类型支持的范围内
使用static定义类型属性。在为类定义计算类型属性时,可以使用关键字class来支持子类对父类的实现
struct TestStruct {
static var string = "structString"
static var value:Int {
return 1
}
}
enum TestEnum {
static var string = "enumString"
static var value:Int {
return 2
}
}
class TestClass {
static var string = "classString"
static var value:Int {
return 3
}
}
//2、获取和设置属性
print(TestStruct.string)
TestStruct.string = "structStringChanged"
print(TestStruct.string)
print(TestEnum.value)
print(TestClass.value)
Output:
structString structStringChanged 2 3