<!--
{
  "documentType" : "article",
  "framework" : "Combine",
  "identifier" : "/documentation/Combine/performing-key-value-observing-with-combine",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Performing Key-Value Observing with Combine"
}
-->

# Performing Key-Value Observing with Combine

Expose KVO changes with a Combine publisher.

## Overview

Several frameworks use key-value observing to notify your app of asynchronous changes.
By converting your use of KVO from callbacks and closures to Combine, you can make
your code more elegant and maintainable.

### Monitoring Changes with KVO

In the following example, the type `UserInfo` supports KVO for its `lastLogin` property,
as described in <doc://com.apple.documentation/documentation/Swift/using-key-value-observing-in-swift>. The <doc://com.apple.documentation/documentation/UIKit/UIViewController/viewDidLoad()>
method uses the `observe(_:options:changeHandler:)` method to set up a closure that
handles any change to the property. The closure receives an <doc://com.apple.documentation/documentation/Foundation/NSKeyValueObservedChange>
object that describes the change event, retrieves the <doc://com.apple.documentation/documentation/Foundation/NSKeyValueObservedChange/newValue>
property, and prints it. The <doc://com.apple.documentation/documentation/UIKit/UIViewController/viewDidAppear(_:)>
method changes the value, which calls the closure and prints the message.

```
class UserInfo: NSObject {
    @objc dynamic var lastLogin: Date = Date(timeIntervalSince1970: 0)
}
@objc var userInfo = UserInfo()
var observation: NSKeyValueObservation?

override func viewDidLoad() {
    super.viewDidLoad()
    observation = observe(\.userInfo.lastLogin, options: [.new]) { object, change in
        print ("lastLogin now \(change.newValue!).")
    }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    userInfo.lastLogin = Date()
}
```

### Converting KVO Code to Use Combine

To convert KVO code to Combine, replace the `observe(_:options:changeHandler:)` method
with an <doc://com.apple.documentation/documentation/ObjectiveC/NSObject-swift.class/KeyValueObservingPublisher>.
You get an instance of this publisher by calling `publisher(for:)` on the parent
object, as shown in the following example’s <doc://com.apple.documentation/documentation/UIKit/UIViewController/viewDidLoad()>
method:

```
class UserInfo: NSObject {
    @objc dynamic var lastLogin: Date = Date(timeIntervalSince1970: 0)
}
@objc var userInfo = UserInfo()
var cancellable: Cancellable?

override func viewDidLoad() {
    super.viewDidLoad()
    cancellable = userInfo.publisher(for: \.lastLogin)
        .sink() { date in print ("lastLogin now \(date).") }
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    userInfo.lastLogin = Date()
}
```

The KVO publisher produces elements of the observed type — in this case, <doc://com.apple.documentation/documentation/Foundation/Date>
— rather than <doc://com.apple.documentation/documentation/Foundation/NSKeyValueObservedChange>.
This saves you a step, because you don’t have to unpack the <doc://com.apple.documentation/documentation/Foundation/NSKeyValueObservedChange/newValue>
from the change object, as in the first example.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)