Created
May 11, 2018 15:15
-
-
Save JoshuaSullivan/a924483acefae894127dc638238a190d to your computer and use it in GitHub Desktop.
Here is a playground demonstrating how to set up Swift 4 KVO.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: # Setting up Swift 4 KVO | |
import Foundation | |
//: This class has a pair of properties that can be observied by KVO. | |
//: - Note: This class *must* inheret from `NSObject` in order to posess the KVO functionality. | |
class ObservableClass: NSObject { | |
/// An observable string property. Note that it most be annotated with both "@objc" (expose the property to the | |
/// Objective-C runtime) and "dynamic" (enables KVO for the property). | |
@objc dynamic private(set) var stringProperty: String = "Starting string!" | |
/// An observable Date property. | |
@objc dynamic private(set) var dateProperty: Date = Date() | |
/// A method to update the string property. | |
func updateString(to string: String) { | |
self.stringProperty = string | |
} | |
/// A method to update the date property. | |
func updateDate(secondsSinceNow: TimeInterval) { | |
self.dateProperty = Date(timeIntervalSinceNow: secondsSinceNow) | |
} | |
} | |
//: This is the class which will be observing the changes and letting us know when it happens. | |
class ObservingClass { | |
/// Just a simple date formatter to print out the dates. | |
static let dateFormatter: DateFormatter = { | |
let df = DateFormatter() | |
df.timeStyle = .short | |
df.dateStyle = .medium | |
return df | |
}() | |
/// We use this array to hold on to our KVO observations so that | |
var observations: [NSKeyValueObservation] = [] | |
/// Initialize this class with the object we want to observe. | |
init(observing object: ObservableClass) { | |
//: Here's where we create the KVO observations. Be sure you retian the returned `NSKeyValueObservation` | |
//: object or it will immediately deallocate and the KVO won't occur. | |
//: - Note: There are 2 signatures for this method in auto-complete. The first one omits the `options:` | |
//: parameter due to a default value. However, the default value does not specify that any of | |
//: the values be supplied in the change object (they will all be `nil`). The KVO closure will | |
//: still be triggered, so you can tell that there was a change, but you'd have to manually | |
//: inspect the property to see what the new value was. | |
observations.append(object.observe(\.stringProperty, options: [.new], changeHandler: { (object, change) in | |
guard let nv = change.newValue else { return } | |
print("The string property changed to: \(nv)") | |
})) | |
// Now we'll observe both the old and new values of the date property. | |
observations.append(object.observe(\.dateProperty, options: [.old, .new], changeHandler: { (object, change) in | |
guard let old = change.oldValue, let new = change.newValue else { return } | |
let df = ObservingClass.dateFormatter | |
print("The date changed from \(df.string(from: old)) to \(df.string(from: new)).") | |
})) | |
} | |
func killObservations() { | |
observations = [] | |
} | |
} | |
//: Instantiate our observable and observer classes. | |
let observable = ObservableClass() | |
let observing = ObservingClass(observing: observable) | |
//: Change the observed properties and see the observations trigger. | |
observable.updateString(to: "Oh! The huge manatee!") | |
observable.updateDate(secondsSinceNow: 3600) | |
//: Release the observation objects. | |
observing.killObservations() | |
//: Note that the observation does not trigger when we change the date again. | |
observable.updateDate(secondsSinceNow: 7200) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment