Last active
June 22, 2020 11:26
-
-
Save srstanic/5a974314b7d61bb6967c9b2124aa175d to your computer and use it in GitHub Desktop.
ModelState and ModelStateUpdateNotifier
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
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