前言
在寫swift版的上下拉刷新缎罢,語法看了3個小時就開始動手了般眉,結果一路坑麻顶,先寫幾篇鋪墊的文章巷折,后續(xù)文章會附上上下拉刷新有關代碼遍略。
KVO
Swift對KVO支持可謂差到不行惧所,只能NSObject的子類進行監(jiān)聽,而對基本類型則不執(zhí)行绪杏,寫的時候踩了坑下愈,還不知道為什么,尷尬蕾久。下面記錄踩過的坑势似,提醒后來者。
起因是這樣僧著,我在畫一個貝塞爾曲線履因,想監(jiān)聽控制點的y坐標,結果我寫出下面代碼(下面例子沒有寫removeObserver方法盹愚,你們一定要記得寫哈):
public class SpringView: UIView {
var pointY = 0.0
let keyY = "pointY"
override public init(frame: CGRect) {
super.init(frame: frame)
addObserver(self, forKeyPath: keyY, options: [.old, .new], context: nil)
pointY = 1.0
}
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == keyY {
print(pointY)
}
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
呀搓逾?!為毛不走杯拐!就是因為pointY是基本類型霞篡,此處耽誤一個小時。改一改:
public class SpringView: UIView {
dynamic var point = UIView()
let keyY = "point.frame"
override public init(frame: CGRect) {
super.init(frame: frame)
addObserver(self, forKeyPath: keyY, options: [.old, .new], context: nil)
point.frame = CGRect(x: 10.0, y: 10.0, width: 3.0, height: 3.0)
}
override public func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == keyY {
print(point.frame)
}
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
這次監(jiān)聽了一個view的frame,妥端逼。值得注意的一點朗兵,在需要KVO的屬性前面要加上** dynamic**前綴,告訴編譯器這個是可能被動態(tài)調用的顶滩。上述代碼去掉dynamic一樣正常執(zhí)行余掖,這又是為什么?
這就得說說OC和Swift的不同之處了礁鲁,OC是動態(tài)語言盐欺,我們所謂的執(zhí)行方法, 實際上是發(fā)消息仅醇,而Swift可以靜態(tài)調用方法冗美。當繼承 NSObject 時,就認為是 Objective-C 的類析二,就按照 Objective-C 的方式處理粉洼。注意就算是繼承 NSObject节预,但將方法標記成私有 private,也是不能動態(tài)找到方法地址的属韧。所以安拟,上述代碼中,如果point是private的宵喂,不加dynamic就會報錯糠赦。
那么如何監(jiān)聽基本類型呢?各位自己想辦法锅棕,啊哈哈愉棱,給一篇文章供大家參考KVO。
上述代碼中哲戚,我要監(jiān)聽的都是本類中的屬性奔滑,就真的拿基本類型的屬性沒招了么?那不行顺少,于是我有嘗試了下述方法朋其,還是回到最初情況:
public class SpringView: UIView {
var pointY = 0.0 {
didSet {
print(pointY)
}
}
override public init(frame: CGRect) {
super.init(frame: frame)
changePointY()
}
func changePointY() {
pointY = 1.0
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Swift為我們提供了willSet和didSet兩種監(jiān)聽器,看名字都知道這是干嘛用的脆炎,就不細說了哈梅猿。注意一點,在構造器中直接為屬性賦值不會走聽器的秒裕,可以使用上圖代碼方法或者在監(jiān)聽器中使用KVC賦值袱蚓。
以上是我踩坑的經(jīng)過,希望能給大家一些幫助几蜻。