#KVOについて
まずKVO自体の説明を少し。
KVO(Key Value Observing)とはオブジェクトの値の変更の監視をする技術です。
後付けできるsetter
,getter
をイメージしてもいいかもしれませんし、
delegate
パターンもKVOと似た働きをすることがあります。
ただsetter
,getter
だとオブジェクトそのものに組み込むぶん依存性が上がりやすいですし。
delegate
パターンではdelegate
に設定できるオブジェクトは一つのみで、protocol
でデリゲートを作って行かなくてはなりません。
ここで活躍するのがKVOです。
簡単な例だとこんな感じ
class KVOSample: NSObject{
@objc dynamic var value:Int = 0
}
こうすると後からvalue
の値の変更を監視することができます。
#Swift3.0のKVO
SwiftにはObjC時代から続くKVOの機能があります。
Swift3.0までを例に、WKWebView
のestimatedProgress
の値を監視しようとすると
こんな感じ
class ViewController: UIViewController{
var webView: WKWebView
//中略
override func viewDidLoad(){
//webViewにObserverを追加
webView.addObserver(self, forKeyPath:"estimatedProgress", options:.new, context:nil)
}
//NSObjectのもつメソッドを継承
override func observeValueForKeyPath(keyPath:String, ofObject object:Any, change:[NSObject:Any], context:UnsafeMutablePointer<Void>) {
switch keyPath {
case "estimatedProgress":
if let progress = change[.newKey] as? Float {
print("Progress: \(progress)")
}
default: break
}
}
}
ただなんかやっている事に比べてコードが複雑過ぎますよね。
まず、KeyPathがString指定なので、
ミスタイプを起こしやすいですし、型も明示的にAnyから変換する必要があります。
特にViewControllerでobserveValueForKeyPath
なんて言う長ったらしいコードを継承するのもKVOが好きになれなかった理由です。
#Swift 4.0 のKVO!
Swift4.0になってKVOの実装は非常にシンプルかつ
Swiftらしいものになりました!
KeyPath生成用の独自演算子まで用意してかなりAppleも本気で取り組んでいる感じです。
これを見てください。
class ViewController: UIViewController{
var webView: WKWebView
private var _observers = [NSKeyValueObservation]()
//中略
override func viewDidLoad(){
_observers.append(webview.observe(\.estimatedProgress, options: .new){_,change in
print("Progress: \(change.newValue)")
})
}
}
なかなかスッキリしているでしょう!
それぞれ説明していきます。
###NSObject::observe(keyPath:,options:,changeHandler:)
Swift4.0でNSObjectに以下のメソッドが追加されました。
public func observe<Value>(
_ keyPath: KeyPath<NSObject, Value>, options: NSKeyValueObservingOptions,
changeHandler: @escaping (NSObject, NSKeyValueObservedChange<Value>) -> Void
) -> NSKeyValueObservation
このメソッドの何がすごいかと言うと値の変更をclosureで受け取れるようになるだけでなく
KeyPath
に監視する対象の型を渡せるのです!
なので上記のように明示的型変換をすることなくvalue
を受け取ることができます。
###新演算子 ""
コレについてまとめている情報が少なかったので演算子と定義していいか微妙なところではあるのですが
webview.observe(\.estimatedProgress, options: .new)
このestimatedProgress
の前についているバックスラッシュがKeyPathを生成する演算子です。
省略をしないで書くとこんな感じ
webview.observe(\WKWebView.estimatedProgress, options: .new)
selector
に近い見た目ですがずっとシンプルですよね。
追記:
\
は演算子ではなく式expression
であると
教えていただきました。
こちら
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-ID383
に詳しい情報が乗っているそうです。
#まとめ
Swift4.0で大きく変わったKVOですが
あまりまとめた記事がない印象だったのでまとめてみました。
今までKVOは記述の冗長さからあまり積極的に使ってこなかったのですが
コレからはガンガン使っていこうと思っています(`・ω・´)
ではでは