4
\$\begingroup\$

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>?
}
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jul 10, 2018 at 21:32
\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

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)
 }
 }
}
answered Jul 11, 2018 at 11:13
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.