首先了解两个基本概念 类 实例
//1:类的概念 对全体的共有特性的抽象和封装,是一种类型.
class People{
var name: String = ""
}
/*
知识点:
1):swift定义类的关键字是class.
2):类的结构有以下几个部分:
关键字class开始.
使用{}包含类的主体
class 和{}之间是类名,如上面People.
swift 语言的代码规范是类名使用大写开头.
类名后面可选扩展部分可以是继续也可以是遵守协议.
*/
//2实例
var people1=People()
let prople2=People()
/*
people1,people2就是实例对象.语法如下: 变量类型符号let/var 对象名=类名()
*/
下面来看一下属性:
//定义一个类,添加相应的属性
class People{
let gender: String = "Male" // 性别,存储属性,实例属性
var dream: String? // 梦想,存储属性,实例属性
var reality: String = "" // 现实,存储属性,实例属性
var lover: People? // 爱人,存储属性,实例属性
var isHappy: Bool{ // 你幸福吗?计算属性,实例属性
get{
if dream == reality || lover != nil{ //梦想照进现实或者有爱人
return true
}else{ //梦想很丰富现实很骨干.
return false
}
}
}
class var plant: String{ //生存的新球,地球,计算属性,类型属性.
return "earth"
}
}
/*
上面涉及了存储属性,计算属性,类型属性,实例属性.
从属性归属的角度.可分为类型属性和实例属性.
从属性的使用角度,可分为存储属性,计算属性.
*/
//使用点语法我们可以反问属性:
let jack = People()
jack.reality = "iOS developer!" //给属性赋值
//jack.gender = "Women" 对常量存储属性进行赋值,编译器会提示错误,因为初始化之后其值就不能够改变.
print(jack.reality) //iOS developer
存储属性
存储属性:就是定义在类中的一个变量或者常量,因此有可以分为变量存储属性(使用var定义)和常量存储属性(使用let定义).上面的存储属性都是使用var来定义的,因为不管是梦想,还是爱人,都是可以变化的.但是性别是不变的.惰性存储属性
不仅有存储属性还有惰性存储属性,惰性存储属性是指当第一次被调用的时候才会计算其初始值的属性。好比如:类的有些属性是必须要有的,但不是一开始就有,经常出现在某个属性在类刚初始化的时候是没有的,只有到了一段时间或者某个条件触发后才存在.其定义格式如下: lazy var 变量名
下面看一个有趣的例子: 在我们读书的时候老师经常说"你这熊孩子,平时不烧香,临时抱佛脚!"
//定义一个类,然后给People加上一个惰性存储属性
class Buddha{
var name: String
init(name: String){
self.name = name
}
}
class People{
let gender: String = "Male" // 性别,存储属性,实例属性
var dream: String? // 梦想,存储属性,实例属性
var reality: String = "" // 现实,存储属性,实例属性
var lover: People? // 爱人,存储属性,实例属性
var isHappy: Bool{ // 你幸福吗?计算属性,实例属性
get{
if dream == reality || lover != nil{ //梦想照进现实或者有爱人
return true
}else{ //梦想很丰富现实很骨干.
return false
}
}
}
class var plant: String{ //生存的新球,地球,计算属性,类型属性.
return "earth"
}
lazy var buddha = Buddha(name: "释迦摩尼") //惰性存储属性
func pray(){ //向佛祈祷,寻求帮助
print("佛祖法号:\(buddha.name)")
}
}
let youngCoder = People() //小码农
youngCoder.pray() //作业完不成,只能向佛祖祈祷
/*
lazy var buddha = Buddha(name: "释迦摩尼") //惰性存储属性
这里虽然定义了buddha属性,并且等号右侧出现了Buddha初始化代码,但是这个阶段只做了类型的站位,而不会
开屏任何实际空间给buddha属性,只有等第一次使用时才会分配空间,比如例子中youngCoder.pray() 之后,
buddha属性才会被分配空间.
*/
我们可以通过LLDB 的调试一下,看看惰性属性是不是我们上面所说的那么回事:(分别在调用pray()方法之前和调用之后加相应的断点,并且在控制台输入print youngCoder)在没有调用pray()方法之前,看到如下输出:
buddha.storage=nil,很明显buddha的存储空间是空的.在我们调用了pray()方法之后,我们在一次打印对象youngCoder,可以看到如下输出:
现在就非常明显了,此时的buddha属性有存储空间了,并且有相应的内容.
注意事项:
1):如果在类实例构造时无法知道属性所依赖的外部信息,则使用惰性属性.
2):当属性的值需要复杂或者大量计算时,为了不阻塞对象的初始化,则使用惰性属性.
3):必须将惰性存储属性声明成为变量,因为属性的值在实例构造完成之前可能无法得到.而常量属性在构造过程完成之前必须要有初始值,因此无法声明成常量属性.
计算属性
4大特点:
1):虽然是属性,但是却没有实际的内存空间,在类的结构中不占据内存位置.
2):提供了取值访问器get和赋值访问器set,负责获取该属性的值,或者通过该属性给其他的存储属性负责.
3):为Swift类属性增加了开闭原则.
4):但凡计算属性必须是变量类型(var),因为计算属性值不确定.
看一个使用计算属性的例子:
class People{
let gender: String = "Male" // 性别,存储属性,实例属性
var dream: String? // 梦想,存储属性,实例属性
var reality: String = "" // 现实,存储属性,实例属性
var lover: People? // 爱人,存储属性,实例属性
var appearance: String = ""
var isHappy: Bool{ // 你幸福吗?计算属性,实例属性
get{
//梦想照进现实,或者有爱人,或者帅到睡不着,那就很幸福了!
if dream != "" && (dream == reality) || lover != nil || appearance == "帅到睡不着" {
return true
}else{
return false
}
}
//赋值访问器
set(newIsHappy){
if newIsHappy == true{
appearance = "容光焕发"
}else{
appearance = "苦瓜脸"
}
}
}
}
var oldCoder = People()
//其实,刚开始,老码并不幸福
print("old Coder is happy:\(oldCoder.isHappy)")//false
//如果小伙伴说老码幸福,那么就容光焕发了.
oldCoder.isHappy = true
print("老码的长相:\(oldCoder.appearance)") //老码的长相:容光焕发
上面使用了计算属性:非常简单下面一起来看一下语法:
取值访问器(get)标准格式如下:
var 计算属性: 类型{
get{
return 符合类型的值
}
}
取值访问器(get)精简格式如下:
var 计算属性: 类型{
return 符合类型的值
}
赋值访问器(set)标准格式如下:
var 计算属性: 类型{
set(newValue){
}
}
赋值访问器(set)精简格式如下:
var 计算属性: 类型{
set{}//在精简格式下:set后面省略的参数默认为newValue,所以在set后面的{}实体里可以使用newValue来设置新值.
}
可以使用下面替代之前的(set)代码:
set{
if newValue{
appearance = "容光焕发"
}else{
appearance = "苦瓜脸"
}
}
只读控制
只读控制及开闭规则的实现,对于某些属性我们允许访问而不允许赋值,则称这类属性为只读属性.对外开放访问,对内赋值关闭,这是编程很重要的开闭原则.
比如老码是否开心的属性只能够看,而不能够由外人改变,自己的苦只有自己知道,这种情况下:isHappy就是一个只读属性.
var isHappy: Bool{ // 你幸福吗?计算属性,实例属性
get{
//梦想照进现实,或者有爱人,或者摔到睡不着,那就很幸福了!
if dream != "" && (dream == reality) || lover != nil || appearance == "帅到睡不着" {
return true
}else{
return false
}
}
}
类型属性
static var storedTypeProperty = "Some value"
static var computedTypeProperty: Int {
return 1
}
class var stringComputedProperty: String {
return "string"
}
}
struct SomeStructure {
static var storedTypeProperty = "Some value"
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value"
static var computedTypeProperty: Int {
return 6
}
}
获取和设置类型属性的值
print("\(SomeStructure.storedTypeProperty),\(SomeStructure.computedTypeProperty)")//Some value,1
print(SomeEnumeration.storedTypeProperty) //Some value
print(SomeClass.stringComputedProperty) //string
属性观察器
属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。
class People{
var name: String = ""
var lover: People? { // 爱人,存储属性,实例属性
willSet(newLover){ // lover属性值改变前被触发
if (self.lover != nil){
if (newLover != nil){
print("\(self.name) 移情别恋了 \(newLover!.name)")
}
}else{
if (newLover != nil){
print("\(self.name) 找到了糟糠之妻 \(newLover!.name)")
}
}
}
didSet(oldLover){
if (oldLover != nil){
print("\(self.name) 狠心的离开了 \(oldLover!.name)")
}
}
}
}
var man = People()
man.name = "陈世美"
let lover1 = People()
lover1.name = "秦香莲"
let lover2 = People()
lover2.name = "大宋公主"
man.lover = lover1
man.lover = lover2
/*
属性观察器:
1)属性观察器分为两种:willSet(属性值改变前触发)和didSet(属性值改变后触发),其格式如下:
willSet(willSetValue){
//willSetValue 可以用户自己定义
}
简化格式为:
willSet{
//必须使用newValue作为参数
}
上面willSetValue/newValue代表将要使用的新值.
didSet(oldSetValue){
//oldSetValue 可以用户自己定义
}
简化格式为:
didSet{
//必须使用oldValue作为参数
}
2):属性观察器不能够用在惰性属性上,因为惰性存储属性是根据需要产生的,所以无法确定观察有效期.
3):对于可以重写的属性,可以在其子类中增加观察器,但是对于非重写属性则没有必要,因为可以在其赋值服务器中
触发观察的行为.
*/
lazy
特性。局部范围的常量或变量不会延迟计算。