didSet 在属性新的值被设置之后立即调用,属于属性观察器
属性观察器,属性观察器监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,即使新值和当前值相同的时候也不例外。
可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重写属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。你不必为非重写的计算属性添加属性观察器,因为可以通过它的 setter 直接监控和响应值的变化。
可以为属性添加如下的一个或全部观察器:
willSet
在新的值被设置之前调用didSet
在新的值被设置之后立即调用
willSet
观察器会将新的属性值作为常量参数传入,在 willSet
的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称 newValue
表示。
同样,didSet
观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名 oldValue
。如果在 didSet
方法中再次对该属性赋值,那么新值会覆盖旧的值。
注意
父类的属性在子类的构造器中被赋值时,它在父类中的willSet
和didSet
观察器会被调用,随后才会调用子类的观察器。在父类初始化方法调用之前,子类给属性赋值时,观察器不会被调用。
下面是一个 willSet
和 didSet
实际运用的例子,其中定义了一个名为 StepCounter
的类,用来统计一个人步行时的总步数。这个类可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
stepCounter.totalSteps = 896
// About to set totalSteps to 896
// Added 536 steps
StepCounter
类定义了一个 Int
类型的属性 totalSteps
,它是一个存储属性,包含 willSet
和 didSet
观察器。
当 totalSteps
被设置新值的时候,它的 willSet
和 didSet
观察器都会被调用,即使新值和当前值完全相同时也会被调用。
例子中的 willSet
观察器将表示新值的参数自定义为 newTotalSteps
,这个观察器只是简单的将新的值输出。
didSet
观察器在 totalSteps
的值改变后被调用,它把新值和旧值进行对比,如果总步数增加了,就输出一个消息表示增加了多少步。didSet
没有为旧值提供自定义名称,所以默认值 oldValue
表示旧值的参数名。
注意
如果将属性通过 in-out 方式传入函数,
willSet
和didSet
也会调用。这是因为 in-out 参数采用了拷入拷出模式:即在函数内部使用的是参数的 copy,函数结束后,又对参数重新赋值。
------------------------------------------------------------
本地获取图片资源
Bundle.main.path(forResource:"xxxx.jpg", ofType:nil) 获取本地资源路径
UIImage(contentsOfFile:"本地资源路径")
-------------------------------------------------------------
UIColorBreakForOutOfRangeColorComponents 警告
[Graphics] UIColor created with component values far outside the expected range. Set a breakpoint on UIColorBreakForOutOfRangeColorComponents to debug. This message will only be logged once.
这个警告是创建UIColor的时候的参数溢出,RGB值的范围是[0,1],如果给定一个超出这个值的参数,就会发出这个警告
解决方案:
设置symblic breakpoint断点,具体操作
1.创建断点【Symbolic Breakpoint】
2.添加【Symbol】值:UIColorBreakForOutOfRangeColorComponents
3.运行应用,通过【call stack】找到出问题的代码,修改对应的值为0-1之间的即可解决问题
---------------------------------------------------------------
可选链
可选链式调用(Optional Chaining)是一种可以在当前值可能为nil
的可选值上请求和调用属性、方法及下标的方法。如果可选值有值,那么调用就会成功;如果可选值是nil
,那么调用将返回nil
。多个调用可以连接在一起形成一个调用链,如果其中任何一个节点为nil
,整个调用链都会失败,即返回nil
。
注意
Swift 的可选链式调用和 Objective-C 中向nil
发送消息有些相像,但是 Swift 的可选链式调用可以应用于任意类型,并且能检查调用是否成功。
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
// 打印 “Unable to retrieve the number of rooms.”
----------------------------------------------------------------
as? 或者as! 类型转换
向下转型(Downcasting)
某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用类型转换操作符(as?
或 as!
)。
因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式(conditional form)as?
返回一个你试图向下转成的类型的可选值(optional value)。强制形式 as!
把试图向下转型和强制解包(force-unwraps)转换结果结合为一个操作。
当你不确定向下转型可以成功时,用类型转换的条件形式(as?
)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 nil
。这使你能够检查向下转型是否成功。
只有你可以确定向下转型一定会成功时,才使用强制形式(as!
)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。
下面的例子,迭代了 library
里的每一个 MediaItem
,并打印出适当的描述。要这样做,item
需要真正作为 Movie
或 Song
的类型来使用,而不仅仅是作为 MediaItem
。为了能够在描述中使用 Movie
或 Song
的 director
或 artist
属性,这是必要的。
在这个示例中,数组中的每一个 item
可能是 Movie
或 Song
。事前你不知道每个 item
的真实类型,所以这里使用条件形式的类型转换(as?
)去检查循环里的每次下转:
for item in library {
if let movie = item as? Movie {
print("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as? Song {
print("Song: '\(song.name)', by \(song.artist)")
}
}
// Movie: 'Casablanca', dir. Michael Curtiz
// Song: 'Blue Suede Shoes', by Elvis Presley
// Movie: 'Citizen Kane', dir. Orson Welles
// Song: 'The One And Only', by Chesney Hawkes
// Song: 'Never Gonna Give You Up', by Rick Astley
示例首先试图将 item
下转为 Movie
。因为 item
是一个 MediaItem
类型的实例,它可能是一个 Movie
;同样,它也可能是一个 Song
,或者仅仅是基类 MediaItem
。因为不确定,as?
形式在试图下转时将返回一个可选值。item as? Movie
的返回值是 Movie?
或者说“可选 Movie
”。
当向下转型为 Movie
应用在两个 Song
实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 Movie
真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“if let movie = item as? Movie
”,可以这样解读:
“尝试将 item
转为 Movie
类型。若成功,设置一个新的临时常量 movie
来存储返回的可选 Movie
中的值”
若向下转型成功,然后 movie
的属性将用于打印一个 Movie
实例的描述,包括它的导演的名字 director
。相似的原理被用来检测 Song
实例,当 Song
被找到时则打印它的描述(包含 artist
的名字)。
注意
转换没有真的改变实例或它的值。根本的实例保持不变;只是简单地把它作为它被转换成的类型来使用。