Key-Value Observing (KVO) in Swift 4
Key-Value Observing (KVO), is an important concept in Cocoa API. It allows objects to be notified when the state of another object changes. Here I will explain how you can use this KVO in your swift programming skills where classes are interconnected with each others reference. If there is any change in property defined in custom type such as class then the reference of this custom type in another class should be notified quickly.Lets do some coding {...}
Consider one small class that has definition as
@objcMembers class FirstClass: NSObject {
// MARK: - Properties
var createdAt = Date()
dynamic var updatedAt = Date()
}
Read with attention that the above class is made "@objMembers" and one property is made "dynamic" that could be notified of value changes. Why because the KVO uses Objective-C runtime. And if you forgot to make the required class as @objMembers and required property as dynamic, the KVO will not work.
So for making your KVO successfull make your required class as @objMembers and required property as dynamic.
The Second class whose instance will be used in our UIViewController is as follows
class SecondClass: NSObject {
// MARK: - Properties
var firstClass: FirstClass
// MARK: -
lazy private var dateFormatter: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
return dateFormatter
}()
// MARK: -
var createdAt: String {
return dateFormatter.string(from: firstClass.createdAt)
}
var updatedAt: String {
return dateFormatter.string(from: firstClass.updatedAt)
}
// MARK: - Initialization
init(withFirstClass firstClass: FirstClass) {
self.firstClass = firstClass
super.init()
firstClass.updatedAt = Date()
}
// MARK: - Public Interface
func updateFirstClass() {
firstClass.updatedAt = Date()
}
}
Here the actual implementation of our KVO will happen on ViewController in real scenario.
class ViewController: UIViewController {
let secondClassInst = SecondClass(withFirstClass: FirstClass())
//MARK: this array will hold multiple observations realated to multiple property changes of any models present in this ViewController.
var observers = [NSKeyValueObservation]()
//Mark: This lable will show us the values changed via KVO
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//Mark: KVO Observer applied here
observeModels()
}
}
func observeModels(){
//Mark: since observers variable is an array that's why it can hold multiple NSKeyValueObservation.
self.observers = [self.secondClassInst.firstClass.observe(\FirstClass.updatedAt, changeHandler: { (FirstClassIns, change) in
print("Changes observed on ViewController \(FirstClassIns.updatedAt)")
DispatchQueue.main.async {
self.label.text = "\(self.secondClassInst.updatedAt)"
}
})]
}
Here in above observeModels() function, I had applied only one observation in this array but it will be your TODO to implement and see the multiple property changes and handled at same time by only creating new array element as per your requirement in the observers array.
//Mark: The below button action will update the property with latest DateTime.
@IBAction func updateAction(_ sender: UIButton) {
secondClassInst.updateFirstClass()
}
Here You go with the KVO implemented and the O/P will be as follows.
