I'm using Swift 4.0 and I'm using UserDefaults
in my project for storing Strings like login or something. I have a class:
class Cache: UserDefaultsManager {
static var currentProfileID: Int? {
get {
return value(forKey: Constants.Cache.CurrentProfileID) as? Int
}
set {
set(newValue, forKey: Constants.Cache.CurrentProfileID)
}
}
static var login: String? {
get {
return value(forKey: Constants.Cache.Login) as? String
}
set {
set(newValue, forKey: Constants.Cache.Login)
}
}
// ... and there are more of this kind
, where UserDefaultsManager
looks like this:
class UserDefaultsManager {
private static var uds: UserDefaults {
return UserDefaults.standard
}
static func value(forKey: String) -> Any? {
if let encoded = uds.object(forKey: forKey) as? Data {
return NSKeyedUnarchiver.unarchiveObject(with: encoded)
}
return nil
}
static func set(_ data: Any?, forKey: String) {
let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: data as AnyObject)
uds.set(encodedData, forKey: forKey)
if (!uds.synchronize()) {
NSLog("Failed sync UserDefaults?")
}
}
}
Constants.Cache
is a structure that holds my keys. My question is:
What would be a good approach to make my
Cache
class lighter with less code?
I imagine the final product should look like:
class Cache {
static var hash: UDSObject<String>?
static var currentProfileID: UDSObject<Int>?
static var login: UDSObject<String>?
static var selectedWindowID: UDSObject<Int>?
}
1 Answer 1
Your Cache
class cannot be lighter than it already is. The most you can do is, introduce generics to remove the redundant casting every time you are trying to fetch from user defaults.
However, I see a major problem with the implementation here:
Is Cache also a UserDefaultsManager
? Do you see Cache
as something that extends the functionalities of the UserDefaultsManager
class, or does your Cache
use the functionalities of the UserDefaultsManager
? I feel that composition is the way to go here than inheritance. I'd refactor this code to something like this:
protocol CacheHandling {
func value<T>(forKey: String) -> T?
func set<T>(_ data: T?, forKey: String)
}
extension CacheHandling {
func value<T>(forKey: String) -> T? {
let userDefaults = UserDefaults.standard
if let encoded = userDefaults.object(forKey: forKey) as? Data {
return NSKeyedUnarchiver.unarchiveObject(with: encoded) as? T
}
return nil
}
func set<T>(_ data: T?, forKey: String) {
let userDefaults = UserDefaults.standard
let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: data as AnyObject)
userDefaults.set(encodedData, forKey: forKey)
if (!userDefaults.synchronize()) {
NSLog("Failed sync UserDefaults?")
}
}
}
struct Cache : CacheHandling {
var currentProfileID: Int? {
get {
return value(forKey: Constants.Cache.CurrentProfileID)
}
set {
set(newValue, forKey: Constants.Cache.CurrentProfileID)
}
}
var login: String? {
get {
return value(forKey: Constants.Cache.Login)
}
set {
set(newValue, forKey: Constants.Cache.Login)
}
}
}