Last active
January 29, 2020 18:21
-
-
Save MaximKotliar/997984ea77abba87303b60254cabc1cc to your computer and use it in GitHub Desktop.
This file contains hidden or 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
// | |
// UserDefaultsManagedWrapper.swift | |
// Yoga | |
// | |
// Created by Maxim Kotliar on 11.12.2019. | |
// Copyright © 2019 Wikrgroup. All rights reserved. | |
// | |
import Foundation | |
import Bindy | |
@propertyWrapper | |
class UserDefaultsManaged<T: Codable> { | |
let key: String | |
let defaultValue: T | |
let userDefaults: UserDefaults | |
let projectedValue: Observable<T> | |
private var notificationToken: NSObjectProtocol? | |
init(key: String, defaultValue: T, userDefaults: UserDefaults = .standard) { | |
func currentValue() -> T { | |
userDefaults.value(for: key) ?? defaultValue | |
} | |
self.key = key | |
self.defaultValue = defaultValue | |
self.userDefaults = userDefaults | |
self.projectedValue = Observable(currentValue()) | |
var skipNextChange: Bool = false | |
projectedValue.observe(self) { value in | |
guard !skipNextChange else { return } | |
userDefaults.set(value: value, forKey: key) | |
} | |
notificationToken = | |
NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, | |
object: nil, | |
queue: nil) { [weak self] _ in | |
skipNextChange = true | |
self?.projectedValue.value = currentValue() | |
skipNextChange = false | |
} | |
} | |
var wrappedValue: T { | |
get { | |
return self.projectedValue.value | |
} | |
set { | |
projectedValue.value = newValue | |
} | |
} | |
} | |
extension UserDefaults { | |
private struct CodableWrapper<T: Codable>: Codable { | |
let value: T | |
} | |
func value<T: Codable>(for key: String) -> T? { | |
do { | |
guard let data = self.data(forKey: key) else { return nil } | |
return try JSONDecoder.fromLocalStorage.decode(CodableWrapper<T>.self, from: data).value | |
} catch { | |
return nil | |
} | |
} | |
func set<T: Codable>(value: T?, forKey key: String) { | |
do { | |
guard let value = value else { | |
removeObject(forKey: key) | |
return | |
} | |
let data = try JSONEncoder.toLocalStorage.encode(CodableWrapper(value: value)) | |
set(data, forKey: key) | |
} catch { | |
assertionFailure("Fail to store \(T.self) in keychain, reason: \(error.localizedDescription)") | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment