I'm trying to create a simple mvvm model using kvo
My goal is when the UITextField text changes, automatically change the UILabel text.
But for some reason the observeValue
function is not called
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
var viewModel : TestViewModel?
@IBOutlet weak var LBLABEL: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
viewModel = TestViewModel()
addObserver(self, forKeyPath: #keyPath(viewModel.infoText), options: [.old, .new], context: nil)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
viewModel?.infoText = textField.text
return true
}
// MARK: - Key-Value Observing
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "info" {
// Update Time Label
LBLABEL.text = viewModel?.infoText
}
}
}
class TestViewModel : NSObject{
var model : TestModel
var infoText:String? {
didSet{
model.info = self.infoText
}
}
override init() {
model = TestModel()
}
}
class TestModel {
var info:String?
}
I already tried to change the observer's declaration or even the ViewModel gets and sets and never succeeded
UPDATE
According to Apple docs, creating an observer for the key path will be much simpler in Swift 4.
class MyObserver: NSObject {
@objc var objectToObserve: MyObjectToObserve
var observation: NSKeyValueObservation?
init(object: MyObjectToObserve) {
objectToObserve = object
super.init()
observation = observe(\.objectToObserve.myDate) { object, change in
print("Observed a change to \(object.objectToObserve).myDate, updated to: \(object.objectToObserve.myDate)")
}
}
}
let observed = MyObjectToObserve()
let observer = MyObserver(object: observed)
observed.updateDate()
You need to add dynamic
to the properties of NSObject
subclass you want to observe. In your case:
@objc dynamic var infoText:String? {
didSet{
model.info = self.infoText
}
}
Btw, I don't know why you want to you textField:shouldChangeCharactersIn as it gets the textfield value before updated. Also, keyPath == "info"
won't never be true. Shouldn't it be something else. E.g., keyPath == "viewModel.infoText"
?