Skip to content

Instantly share code, notes, and snippets.

@GRGBISHOW
Last active February 23, 2024 08:23
Show Gist options
  • Save GRGBISHOW/de88a8e8e2eaccc0140adebb39768ef0 to your computer and use it in GitHub Desktop.
Save GRGBISHOW/de88a8e8e2eaccc0140adebb39768ef0 to your computer and use it in GitHub Desktop.
Testable UserDefault's property wrapper
@propertyWrapper struct UserDefaultsStore<T:Codable> {
let key: String
let storage: UserDefaultsStorage
private let subject: PassthroughSubject<[T], Never> = .init()
var wrappedValue: [T] {
get {
guard let data = storage.object(forKey: key) as? Data,
let models = try? JSONDecoder().decode([T].self, from: data) else {
return []
}
return models
}
set {
if let encoded = try? JSONEncoder().encode(newValue) {
storage.set(encoded, forKey: key)
subject.send(wrappedValue)
}
}
}
var projectedValue: AnyPublisher<[T], Never> {
return subject.eraseToAnyPublisher()
}
}
protocol UserDefaultsStorage {
func object(forKey key: String) -> Any?
func set(_ value: Any?, forKey key: String)
}
extension UserDefaults: UserDefaultsStorage {}
struct DataToSave: Codable {}
//Usage
// Main Target
enum StorageSettings {
@UserDefaultsStore<DataToSave>(key:"stored_locations", storage: DIInjecter.userDefaults)
static var storeSomething: [DataToSave]
}
struct DependenciesInjecter {
lazy var userDefaults: UserDefaultsStorage = UserDefaults.standard
}
var DIInjecter = DependenciesInjecter()
// Test Target
class UserDefaultsStorageMock: UserDefaultsStorage {
var values: [String: Any]
init(values: [String : Any] = [:]) {
self.values = values
}
func object(forKey key: String) -> Any? {
return values[key]
}
func set(_ value: Any?, forKey key: String) {
values[key] = value
}
}
extension DependenciesInjecter {
static var mock: DependenciesInjecter {
Self(userDefaults: UserDefaultsStorageMock())
}
}
// Put it in setup func
DIInjecter = .mock
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment