KVOは(Key-Value Observing)変数の値の変化を監視する仕組みです。
Swiftでは使ったことがなかったので試してみました。
ViewControllerにボタンを配置して、ボタンを押した時に変数の値を変えるテストプログラムを作成し動作確認します。
ViewControllerで監視するクラスを作成し、このインスタンス変数を監視します。
import Foundation
class Hoge : NSObject {
@objc dynamic var count: Int = 0
}
import UIKit
class ViewController: UIViewController {
var hoge: Hoge = Hoge()
override func viewDidLoad() {
super.viewDidLoad()
// countを監視対象にする
hoge.addObserver(self, forKeyPath: "count", options: [.old, .new], context: nil)
hoge.count = 10
hoge.count = 11
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
deinit {
// countを監視対象から削除
hoge.removeObserver(self, forKeyPath: "cout")
}
@IBAction func tapCountBugtton(sender: Any){
print("----- tapCountBugtton")
hoge.count += 1
print("hoge.count : \(hoge.count)")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print("----- observeValue")
print("object : \(String(describing: object))")
print("keyPath : \(String(describing: keyPath))")
print("change : \(String(describing: change))")
}
}
ボタンをタップするとtapCountBugttonが実行されてhoge.countをインクリメントします。
### 出力結果
viewDidLoadでhoge.countに10を代入し、そのあとに11を代入しているのでobserveValueが2回呼ばれまています。
addObserverのoptionsで.oldと.newを指定しているのでchangeに新しい値と古い値が入っています。
----- observeValue
object : Optional(<KvoTest.Hoge: 0x600000016bc0>)
keyPath : Optional("count")
change : Optional([__C.NSKeyValueChangeKey(_rawValue: new): 10, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 0])
----- observeValue
object : Optional(<KvoTest.Hoge: 0x600000016bc0>)
keyPath : Optional("count")
change : Optional([__C.NSKeyValueChangeKey(_rawValue: new): 11, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 10])
ボタンをタップするとtapCountBugttonが実行され、hoge.countをインクリメントしています。
hoge.countの値が変わるのでobserveValueが呼ばれます。
----- tapCountBugtton
----- observeValue
object : Optional(<KvoTest.Hoge: 0x600000016bc0>)
keyPath : Optional("count")
change : Optional([__C.NSKeyValueChangeKey(_rawValue: new): 12, __C.NSKeyValueChangeKey(_rawValue: kind): 1, __C.NSKeyValueChangeKey(_rawValue: old): 11])
hoge.count : 12
Objective-Cの時代からあったKVOなので簡単に動くと思ったのですが、
ちょっとハマってしまいました。
最初、Hogeクラスのcountを下記のように定義していました。
これではKVOはうまく動きませんでした。
var count: Int = 0
下記のようにobjc dynamicを指定すると正常に動作します。
@objc dynamic var count: Int = 0
監視対象の変数にはdynamicの指定が必要なようです。
Swift4からobjcの指定が必要になったようです。