Key-Value Observing (KVO) and Key-Value Coding (KVC) are part of Cocoa’s mechanism inherited from Objective-C, and require to use NSObject and dynamic dispatch through Objective-C runtime.
In short, KVO is for observing property changes, while KVC allows dynamic access to property values using string keys. Both are powerful tools for interacting with properties.
KVO is used for observing changes to the properties of an object. When a property value changes, observers are notified. It’s typically used to observe changes to properties, often for purposes like updating UI elements when data changes, responding to model changes, etc.
KVO relies on the Objective-C runtime to observe changes to properties. The observed object must subclass NSObject, and the observed properties must be marked with @objc dynamic
attributes, @objc
means you want your Swift code to be visible from Objective-C, dynamic
means you want to use Objective-C dynamic dispatch.
import Foundation
class BankAccount: NSObject {
@objc dynamic var balance: Double = 0.0
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) {
if balance >= amount {
balance -= amount
} else {
print("Insufficient funds!")
}
}
}
class AccountManager: NSObject {
@objc var accountToMonitor: BankAccount
var balanceObservation: NSKeyValueObservation?
init(account: BankAccount) {
accountToMonitor = account
super.init()
// Set up KVO for the balance property
balanceObservation = observe(
\.accountToMonitor.balance,
options: [.old, .new]
) { object, change in
if let newBalance = change.newValue {
print("Balance changed: $\(newBalance)")
}
}
}
}
// Create a bank account
let myAccount = BankAccount()
// Create an account manager to observe the account
let manager = AccountManager(account: myAccount)
// Perform some transactions
myAccount.deposit(amount: 1000)
myAccount.withdraw(amount: 500)
myAccount.deposit(amount: 200)
// Clean up (remove the observer)
manager.balanceObservation = nil
When the balance changes, it prints the updated balance:
Balance changed: $1000.0
Balance changed: $500.0
Balance changed: $700.0
It’s similar to property observers (willSet
and didSet
), but KVO is for adding observers outside of the type definition. Be mindful of what you observe. Over-observing properties can clutter your code and impact performance.
KVC is used for accessing an object’s properties indirectly through string-based keys. It allows getting and setting property values dynamically using strings. It’s typically used when you need to access properties dynamically, such as when parsing JSON, dealing with user defaults, or when working with dictionaries.
KVC also relies on the Objective-C runtime for dynamic property access. Similarly, the class must subclass NSObject, and properties need to be marked with @objc
.
import Foundation
class Product: NSObject {
@objc dynamic var productName: String = ""
@objc dynamic var price: Double = 0.0
}
let myProduct = Product()
// Set values using KVC (Key-Value Coding)
myProduct.setValue("Smartphone", forKey: "productName")
myProduct.setValue(799.99, forKey: "price")
// Retrieve values using KVC
if let productName = myProduct.value(forKey: "productName") as? String {
print("Product Name: \(productName)")
}
// Accessing using dot notation for comparison
print("Price: $\(myProduct.price)")
Output:
Product Name: Smartphone
Price: $799.99
While KVO and KVC are powerful features in Apple frameworks, their usage in modern Swift development has somewhat declined in favor of more modern approaches and patterns.
Here’s why their popularity has waned:
willSet
and didSet
) provide a cleaner way to observe property changes compared to KVO.When working with existing Objective-C codebases that heavily rely on KVO and KVC, you might need to use them for compatibility.