Last active
September 13, 2021 21:28
-
-
Save tadija/7668382ef3e14cb304b31b6273ae8f65 to your computer and use it in GitHub Desktop.
AEStoredWrapper
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
/** | |
* https://gist.github.com/tadija/7668382ef3e14cb304b31b6273ae8f65 | |
* Revision 2 | |
* Copyright © 2021 Marko Tadić | |
* Licensed under the MIT license | |
*/ | |
import Foundation | |
public struct AEStoredWrapper { | |
public static var storage: UserDefaults = .standard | |
} | |
// MARK: - Wrappers | |
@propertyWrapper | |
public struct StoredValue<T> { | |
public let key: String | |
public let value: T | |
public let storage: UserDefaults | |
public var wrappedValue: T { | |
get { | |
storage.object(forKey: key) as? T ?? value | |
} | |
set { | |
if let optional = newValue as? AnyOptional, optional.isNil { | |
storage.removeObject(forKey: key) | |
} else { | |
storage.set(newValue, forKey: key) | |
} | |
} | |
} | |
public init( | |
wrappedValue value: T, | |
key: String, | |
storage: UserDefaults = AEStoredWrapper.storage | |
) { | |
self.value = value | |
self.key = key | |
self.storage = storage | |
} | |
} | |
@propertyWrapper | |
public struct StoredRaw<T: RawRepresentable> { | |
public let key: String | |
public let value: T | |
public let storage: UserDefaults | |
public var wrappedValue: T { | |
get { | |
guard let object = storage.object(forKey: key) as? T.RawValue else { | |
return value | |
} | |
return T(rawValue: object) ?? value | |
} | |
set { | |
if let optional = newValue as? AnyOptional, optional.isNil { | |
storage.removeObject(forKey: key) | |
} else { | |
storage.set(newValue.rawValue, forKey: key) | |
} | |
} | |
} | |
public init( | |
wrappedValue value: T, | |
key: String, | |
storage: UserDefaults = AEStoredWrapper.storage | |
) { | |
self.value = value | |
self.key = key | |
self.storage = storage | |
} | |
} | |
@propertyWrapper | |
public struct StoredCodable<T: Codable> { | |
public let key: String | |
public let value: T | |
public let storage: UserDefaults | |
public var wrappedValue: T { | |
get { | |
guard let data = storage.object(forKey: key) as? Data else { | |
return value | |
} | |
if let decoded = try? JSONDecoder().decode(T.self, from: data) { | |
return decoded | |
} else { | |
assertionFailure("decoding failed for key: \(key)") | |
return value | |
} | |
} | |
set { | |
if let optional = newValue as? AnyOptional, optional.isNil { | |
storage.removeObject(forKey: key) | |
} else { | |
if let encoded = try? JSONEncoder().encode(newValue) { | |
storage.set(encoded, forKey: key) | |
} else { | |
assertionFailure("encoding failed for key: \(key)") | |
} | |
} | |
} | |
} | |
public init( | |
wrappedValue value: T, | |
key: String, | |
storage: UserDefaults = AEStoredWrapper.storage | |
) { | |
self.value = value | |
self.key = key | |
self.storage = storage | |
} | |
} | |
// MARK: - Convenience | |
public extension StoredValue where T: ExpressibleByNilLiteral { | |
init(key: String, storage: UserDefaults = AEStoredWrapper.storage) { | |
self.init(wrappedValue: nil, key: key, storage: storage) | |
} | |
} | |
public extension StoredRaw where T: ExpressibleByNilLiteral { | |
init(key: String, storage: UserDefaults = AEStoredWrapper.storage) { | |
self.init(wrappedValue: nil, key: key, storage: storage) | |
} | |
} | |
public extension StoredCodable where T: ExpressibleByNilLiteral { | |
init(key: String, storage: UserDefaults = AEStoredWrapper.storage) { | |
self.init(wrappedValue: nil, key: key, storage: storage) | |
} | |
} | |
// MARK: - Helpers | |
private protocol AnyOptional { | |
var isNil: Bool { get } | |
} | |
extension Optional: AnyOptional { | |
var isNil: Bool { self == nil } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment