KVO: Swift's Built-In Observer Pattern
KVO lets an object subscribe to property changes on another object automatically. It shines when you need UI updates driven by model state, but forgetting to remove observers before deallocation crashes your app with an NSException.
WHY IT EXISTS: Before SwiftUI and Combine, UIKit needed a way to react to data changes without tight coupling. Delegation works for one-to-one relationships, but what if many objects care about a single property? KVO was created to give any object the ability to subscribe to changes on another object's properties through the Objective-C runtime, enabling one-to-many automatic propagation without the observed object knowing who is listening.
THE MENTAL MODEL: Think of KVO like a doorbell system. The house does not know who is standing outside, but when someone presses the button by changing a property, the bell rings and every listener registered to that circuit gets notified. The house did not plan for any specific visitor; it just exposes a signal that the wiring carries to whoever subscribed.
HOW IT WORKS: To observe a property, the observer calls addObserver on the target for a key path. The target must be an NSObject subclass and the observed property must be marked dynamic or belong to a class where the Objective-C runtime can swizzle the setter. When the setter fires, the runtime dispatches observeValue to every registered observer with change details including old and new values. In modern Swift, you can also use the observe method which returns an NSKeyValueObservation token. Keeping that token alive retains the subscription, and letting it deallocate removes the observer automatically.
WHEN TO USE IT: Reach for KVO when you need loose, one-to-many observation of property changes on NSObject-based classes and you cannot modify the source class to add a delegate protocol. Common scenarios include observing system objects like OperationQueue, URLSessionTask, or AVPlayer properties such as isFinished or status where Apple provides KVO compliance but no Swift-native async stream.
WHEN NOT TO USE IT: Do not use KVO on pure Swift structs or classes that do not inherit from NSObject. Do not use it when you own both sides of the relationship and can use a simple closure, delegate, or Combine publisher instead. Avoid it if your team values type safety, because key paths in the old API are stringly typed and runtime mismatches throw exceptions. If you need complex coordination of multiple changing values, KVO's single-property granularity becomes verbose and error-prone.
ONE CANONICAL EXAMPLE: A download manager wraps a URLSessionTask. The view controller needs to update a progress bar as bytes download. Instead of polling or inventing a delegate protocol for a system class, the view controller calls task.progress.addObserver and implements observeValue. When bytes transfer, the UI updates automatically. The footgun appears if the view controller deallocates without removing itself; the next progress update messages a zombie and the app crashes.
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.