Skip to content

Instantly share code, notes, and snippets.

@srstanic
Last active June 22, 2020 11:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save srstanic/5a974314b7d61bb6967c9b2124aa175d to your computer and use it in GitHub Desktop.
Save srstanic/5a974314b7d61bb6967c9b2124aa175d to your computer and use it in GitHub Desktop.
ModelState and ModelStateUpdateNotifier
import Foundation
protocol ModelStateDelegate: class {
func onModelStateOutdated()
}
class ModelState {
weak var delegate: ModelStateDelegate?
init(updateNotification: Foundation.Notification.Name, itemId: String? = nil, outdated: Bool = true) {
self.itemId = itemId
self.isModelOutdated = outdated
if outdated {
modelOutdatedTimestamp = .now
}
let notificationCenter = NotificationCenter.default
self.observer = notificationCenter.addObserver(forName: updateNotification, object: nil, queue: nil) { notification in
if let payload = notification.object as? Dictionary<String, String>,
let receivedItemId = payload[notificationPayloadKey],
self.itemId != nil
{
self.isModelOutdated = self.itemId == receivedItemId
} else {
self.isModelOutdated = true
}
if self.isModelOutdated {
self.modelOutdatedTimestamp = .now
self.delegate?.onModelStateOutdated()
}
}
}
deinit {
NotificationCenter.default.removeObserver(observer as Any)
}
private var observer: NSObjectProtocol?
private var isModelOutdated: Bool
private var modelOutdatedTimestamp: Date?
private var modelUpdatingStartedTimestamp: Date?
private var isModelUpdating: Bool = false
private let itemId: String?
var isOutdated: Bool {
return isModelOutdated
}
var isUpdating: Bool {
return isModelUpdating
}
func startedUpdating() {
isModelUpdating = true
modelUpdatingStartedTimestamp = .now
}
func endedUpdating(updated: Bool) {
isModelUpdating = false
if updated {
guard let startedUpdatingTimestamp = modelUpdatingStartedTimestamp else {
// caller didn't call startedUpdating() so we can't be sure, but let's assume that model is up to date
isModelOutdated = false
modelOutdatedTimestamp = nil
return
}
guard let outdatedTimestamp = modelOutdatedTimestamp else {
// we weren't aware that the model is outdated even before the update, but it definitely should be up to date now
isModelOutdated = false
modelUpdatingStartedTimestamp = nil
return
}
if startedUpdatingTimestamp > outdatedTimestamp {
isModelOutdated = false
} // else model is still outdated because the updateNotification came after the caller started updating
// clean up
modelOutdatedTimestamp = nil
modelUpdatingStartedTimestamp = nil
}
}
}
class ModelStateUpdateNotifier {
init(updateNotification: Foundation.Notification.Name) {
self.updateNotification = updateNotification
}
private let updateNotification: Foundation.Notification.Name
func notifyModelStateChange(for itemId: String? = nil) {
var payload: [String: String]? = [:]
if itemId != nil {
payload![notificationPayloadKey] = itemId
} else {
payload = nil
}
NotificationCenter.default.post(name: updateNotification, object: payload)
}
}
private let notificationPayloadKey = "itemId"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment