Updated 25 March 2021
We all need variables or properties to store any values in them. The navigation of the program depends on the values stored in the defined variables. What happens when the values in the defined data structure change? We have to implement the logic for any values in the variable. Here comes the role of the KVO and KVC in Swift.
Changes in the properties can be observed using Notification-Centre also.
We can send a notification to notify an observing property about the change and perform the actions based on the value that was changed.
Using Notification Centre for a large number of properties will lead to a large number of notifications to send and thus making the code bulkier. To avoid this we use KVO(Key-Value Observing).
KVO is directly related to the KVC(Key-Value Coding)
First, we need to understand what is KVC?
According to Apple:
Key-value coding is a mechanism for accessing an object’s properties indirectly, using strings to identify properties, rather than through invocation of an accessor method or accessing them directly through instance variables.
NSObject confirms to NSKeyValueCoding protocol, so any class that is inherited from NSObject directly conforms to the NSKeyValueCoding protocol.
KVC is generally a coding mechanism that we follow to get or set any property values. The working of the KVC is more like the Dictionaries.
From the below example it will be clear how to use KVC.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class DemoClass: NSObject { @objc dynamic var anyVariable: String! override init() { self.anyVariable = "" super.init() } func setValues(anyVariable: String) { self.willChangeValue(forKey: "setanyVariable") self.anyVariable = anyVariable self.didChangeValue(forKey: "setanyVariable") } override class func automaticallyNotifiesObservers(forKey key: String) -> Bool { if key == "setanyVariable" { return false } else { return super.automaticallyNotifiesObservers(forKey: key) } } } |
We would generally initialize the properties in DemoClass like
1 2 3 4 |
override init(){ self.demoName = "xyz" self.demoAddress = "abc" } |
With KVC we follow the below syntax to set and retrieve values of the properties.
self.setValue: Any for key: key/KeyPath
1 |
self.abc.setValue("initial name for variable", forKey: "setanyVariable") |
For retrieving values :
1 |
let newVariable = self.abc.value(forKey: "setanyVariable") as! String |
Here we are setting and getting the values in property using the Key. We can set or get the values by KeyPath also.
KeyPath represents the absolute path to the property.
Using dot-syntax we can reach out to the property.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class DemoClass: NSObject { @objc dynamic var anyVariable: String! @objc dynamic var otherVariable : OtherVariable! override init() { self.anyVariable = "" super.init() } func setValues(anyVariable: String) { self.willChangeValue(forKey: "setanyVariable") self.anyVariable = anyVariable self.didChangeValue(forKey: "setanyVariable") } override class func automaticallyNotifiesObservers(forKey key: String) -> Bool { if key == "setanyVariable" { return false } else { return super.automaticallyNotifiesObservers(forKey: key) } } } class OtherVariable : NSObject{ @objc dynamic var someOtherVariable : String! override init(){ self.someOtherVariable = "anyVal" } } |
1 2 |
var details : DemoClass self.anyVariable.setValue( “123456”, forKey: details.otherVariable.someOtherVariable) |
In KVO we observe the change in the values of the properties. This can be achieved using NSNotifications.
We have to keep in mind some steps before using KVO, these are:
1 2 |
var abcContext = UnsafeMutableRawPointer.allocate(byteCount: 4 * 4, alignment: 1) self.abc.addObserver(self, forKeyPath: "setanyVariable", options:[.new, .old], context: abcContext) |
Note: Add the observer for the observing property inside the viewDidLoad() or viewWillAppear() method.
Above mentioned parameters are:
We have to implement the below function in order to observe the change in the property
1 2 3 4 5 6 7 |
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if context == abcContext { if keyPath == "setanyVariable" { print("anyVariable changed") } } } |
Inside this method, we can perform any logic for any keyPath.
The main disadvantage of this method is that we have to check the change in the values for each key/keyPath.
The best example of KVO and KVC is how UserDefaults uses this mechanism to set, change and modify the values.
1 |
UserDefaults.standard().set("anyValue", forKey: "AnyKey") |
Please click here to know how Apple describes KVO and KVC
Thanks for reading!!
For other blogs Please click here
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
Be the first to comment.