Skip to content

Instantly share code, notes, and snippets.

@VAnsimov
Last active November 3, 2020 14:28
Show Gist options
  • Save VAnsimov/b5f6f87d2854d9a9ab87a72c408af1be to your computer and use it in GitHub Desktop.
Save VAnsimov/b5f6f87d2854d9a9ab87a72c408af1be to your computer and use it in GitHub Desktop.
UserDefaultsWrapper
import Foundation
private protocol AnyOptional {
var isNil: Bool { get }
}
extension Optional: AnyOptional {
var isNil: Bool { self == nil }
}
protocol ActionUserDefault {
func removeObject()
}
/// - Parameters:
/// - key: Data will be saved and extracted using this key
/// - defaultValue: This value will be substituted when there is no value
/// - userDefaults: NSUserDefaults is a hierarchical persistent interprocess (optionally distributed) key-value store, optimized for storing user settings.
///
/// Types an UserDefaultsWrapper can work with:
///```
/// URL?
/// [Any]?
/// [String : Any]?
/// String?
/// [String]?
/// Data?
/// Bool
/// Int
/// Float
/// Double
/// ```
///
/// - Warning:
/// If the type is not optional, default == nil will cause a crash.
///
/// Exemple:
/// ```
/// class User {
/// @UserDefaultsWrapper<String>(key: "FirstName", default: "John") var firstName
/// // OR
/// @UserDefaultsWrapper(key: "LastName", default: "John") var lastName: String
///
/// @UserDefaultsWrapper(key: "Age") var age: Int?
/// // OR
/// @UserDefaultsWrapper(key: "Old", default: 6) var old: Int?
///}
///
///let user = User()
///print(user.firstName) // John
///user.firstName = "Misha"
///print(user.firstName) // Misha
///$user.firstName.removeObject()
///
///print(user.old) // optional(6)
///user.old = 18
///print(user.old) // optional(18)
///user.old = nil
///print(user.old) // optional(6)
///
///print(user.age) // nil
///user.age = 18
///print(user.age) // optional(18)
///user.age = nil
///print(user.age) // nil
/// ```
@propertyWrapper struct UserDefaultsWrapper<T> {
private let key: String
private let defaultValue: T!
private let userDefaults: UserDefaults
var wrappedValue: T {
get {
let anyValue = userDefaults.value(forKey: key)
let value: T = (anyValue as? T) ?? defaultValue
return value
}
set {
if let optional = newValue as? AnyOptional, optional.isNil {
userDefaults.removeObject(forKey: key)
if let defaultValue = defaultValue {
self.set(newValue: defaultValue)
}
} else {
self.set(newValue: newValue)
}
userDefaults.synchronize()
}
}
var projectedValue: ActionUserDefault { self }
/// - Parameters:
/// - key: Data will be saved and extracted using this key
/// - defaultValue: This value will be substituted when there is no value
/// - userDefaults: NSUserDefaults is a hierarchical persistent interprocess (optionally distributed) key-value store, optimized for storing user settings.
///
/// - Warning:
/// If the type is not optional, default == nil will cause a crash.
init(key: String, default defaultValue: T? = nil, userDefaults: UserDefaults = .standard) {
self.key = key
self.userDefaults = userDefaults
self.defaultValue = defaultValue
}
private func set(newValue: T) {
userDefaults.setValue(newValue, forKey: key)
}
}
// MARK: - ActionUserDefault
extension UserDefaultsWrapper: ActionUserDefault {
func removeObject() {
userDefaults.removeObject(forKey: key)
if let defaultValue = defaultValue {
self.set(newValue: defaultValue)
}
}
}
@VAnsimov
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment