// LoopFollow // UserDefaultsValueGroups.swift import Foundation /// UserDefaultValue groups manager class, providing change observation capabilities (keep clients informed when a change occured in a given group). class UserDefaultsValueGroups { class func values(from groupName: String) -> [UserDefaultsAnyValue]? { return groupNameToValues[groupName] } class func add(_ value: UserDefaultsAnyValue, to groupName: String) { // add to "value-key to groupNames" dictionary var groupNames = valueKeyToGroupNames[value.key] ?? [] guard !groupNames.contains(groupName) else { // already added value to this group! return } groupNames.append(groupName) valueKeyToGroupNames[value.key] = groupNames // add to "groupName to value" dictionary var values = groupNameToValues[groupName] ?? [] values.append(value) groupNameToValues[groupName] = values } @discardableResult class func observeChanges(in groupName: String, using closure: @escaping (UserDefaultsAnyValue, String) -> Void) -> ObservationToken { let id = UUID() var observers = groupNameToObservers[groupName] ?? [:] observers[id] = closure groupNameToObservers[groupName] = observers return ObservationToken { groupNameToObservers[groupName]?.removeValue(forKey: id) } } // called by UserDefaultsValue instances when value changes class func valueChanged(_ value: UserDefaultsAnyValue) { valueKeyToGroupNames[value.key]?.forEach { groupName in notifyValueChanged(value, in: groupName) } } private class func notifyValueChanged(_ value: UserDefaultsAnyValue, in groupName: String) { groupNameToObservers[groupName]?.values.forEach { closure in closure(value, groupName) } } private static var groupNameToValues: [String: [UserDefaultsAnyValue]] = [:] private static var valueKeyToGroupNames: [String: [String]] = [:] private static var groupNameToObservers: [String: [UUID: (UserDefaultsAnyValue, String) -> Void]] = [:] } // user default values group definitions extension UserDefaultsValueGroups { enum GroupNames { static let watchSync = "watchSync" static let alarm = "alarm" } }