Skip to content

Instantly share code, notes, and snippets.

@amrangry
Last active February 5, 2024 17:19
Show Gist options
  • Save amrangry/6920e74fc50bad3e2f2c213a28403b5f to your computer and use it in GitHub Desktop.
Save amrangry/6920e74fc50bad3e2f2c213a28403b5f to your computer and use it in GitHub Desktop.
UserDefaultsManager is a manager and wrapper class for UserDefaults
//
// UserDefaultsManager.swift
// Www.ADKATech.com
//
// Created by AmrAngry on 7/30/19.
// Modifyed by AmrAngry on 5/5/20.
// Copyright © 2019 Www.ADKATech.com. All rights reserved.
// Generic use original mestion by (FB)محمود زكى and hamada147(Github)
import Foundation
/*
//How to use
UserDefaultsManager.shared.set(true, forKey: .admin)
let isAdminEnable = UserDefaultsManager.shared.get(objectForkey: .admin, type: Bool.self)
print(isAdminEnable)
UserDefaultsManager.shared.purge()
print(UserDefaultsManager.shared.get(objectForkey: .admin, type: Bool.self))
*/
/// UserDefaultsManager is a manager and wrapper class for UserDefaults that use for persistance key-value store, optimized for storing user settings.
/// Key-Value Store: NSUserDefaults stores Property List objects (NSString, NSData, NSNumber, NSDate, NSArray, and NSDictionary) identified by NSString keys, similar to an NSMutableDictionary.
/// Optimized for storing user settings: NSUserDefaults is intended for relatively small amounts of data, queried very frequently, and modified occasionally. Using it in other ways may be slow or use more memory than solutions more suited to those uses.
class UserDefaultsManager: NSObject {
/// static shared instance Initializes of `self` with default strategies.
static let shared = UserDefaultsManager()
let userDefaults: UserDefaults?
/// Initializes private`self` with default strategies.
private override init() {
userDefaults = UserDefaults.standard
}
/// -removeObjectForKey: is equivalent to -[... setObject:nil forKey:defaultName]
func remove(for key: UserDefaultsKeys) {
userDefaults?.removeObject(forKey: key.value)
}
func purge() {
let keys = UserDefaultsKeys.allCases//UserDefaultsKeys.reteriveAllCases()
keys.forEach {
let excluded = UserDefaultsKeys.excludedCases.contains($0)
if excluded {
print("excluded case:\($0.value)")
} else {
remove(for: $0)
}
}
//KeyChainWrapper.share.deletePassword()
}
}
extension UserDefaultsManager {
/// set value:forKey: immediately stores a value (or removes the value if nil is passed as the value) for the provided key in the search list entry for the receiver's suite name in the current user and any host, then asynchronously stores the value persistently, where it is made available to other processes.
/// - Parameters:
/// - value: value of any Object confirm to Encodable Protocol
/// - key: String value assocaited with stored object
func set<T>(_ value: T?, forKey key: UserDefaultsKeys) where T: Encodable {
guard let tempValue = value else {
userDefaults?.set(nil, forKey: key.value)
return
}
let jsonEncoder = JSONEncoder()
guard let jsonData = try? jsonEncoder.encode(tempValue) else {
userDefaults?.set(nil, forKey: key.value)
return
}
let json = String(data: jsonData, encoding: .utf8)
userDefaults?.set(json, forKey: key.value)
}
/// Retrive Object assocaited with key
/// - Parameters:
/// - key: UserDefaultsKeys value that use to store value as reference
/// - type: Type of object that conform Decodable Protocol
func get<T: Decodable>(objectForkey key: UserDefaultsKeys, type: T.Type) -> T? {
let jsonString = getObject(key.value) as? String
let jsonData = jsonString?.data(using: .utf8)
let decoder = JSONDecoder()
return try? decoder.decode(type, from: jsonData ?? Data())
}
/**
-set bool:forKey: immediately stores a value for the provided key in the search list entry for the receiver's suite name in the current user and any host, then asynchronously stores the value persistently, where it is made available to other processes.
*/
func set(bool: Bool, for key: UserDefaultsKeys) {
userDefaults?.set(bool, forKey: key.value)
}
/// Retrive Bool assocaited with key
/// - Parameter key: UserDefaultsKeys enum
func get(for key: UserDefaultsKeys) -> Bool? {
let result = userDefaults?.bool(forKey: key.value)
return result
}
}
extension UserDefaultsManager {
/// Retrive Object assocaited with key
/// - Parameter key: UserDefaultsKeys value that use to store value as reference
private func getObject(_ key: String) -> Any? {
return userDefaults?.object(forKey: key)
}
}
enum UserDefaultsKeys: String, CaseIterable {
case currentLoggedinBranch = "currentLoggedinBranch"
case username = "login"
case locationCode = "location_code"
case companyName = "company name"
case companyID = "Current company id"
case lastLoginDate = "lastLoginDate"
case vat = "VAT"
case vatPercentage = "vatperc"
case admin
case serialNumber
case redeamEnabled
case issueEnabled
// no need to purge
case merchantID
case merchantName
case lastUpdateNotification
case theme = "Theme"
case ipAddress = "ip"
case voidKey = "void"
// Helper
static var excludedCases: [UserDefaultsKeys] = [ .voidKey, .ipAddress, .merchantID, .merchantName, .lastUpdateNotification, .theme]
var value : String {
return self.rawValue
}
}
@hamada147
Copy link

I'm personally a huge fan of generic so I had to add it

class UserDefaultManager: NSObject {
    
    static let shared = UserDefaultManager()
    private let userDefaults: UserDefaults?
    
    private override  init() {
        self.userDefaults = UserDefaults.standard
    }
    
    func remove(for key: UserDefaultsKey) {
        self.userDefaults?.removeObject(forKey: key.value)
        self.userDefaults?.synchronize()
    }
    // Genaric is much easier to handle in code
    func set<T>(_ obj: T, for key: UserDefaultsKey) {
        self.userDefaults?.set(object, forKey: key.value)
        self.userDefaults?.synchronize()
    }
    // Genaric is much easier to handle in code
    func get<T>(for key: UserDefaultsKey) -> T? {
        let result = self.userDefaults?.object(forKey: key.value) as? T
        return result
    }
    
    func object(for key: UserDefaultsKey) -> Any? {
        let result = self.userDefaults?.object(forKey: key.value)
        return result
    }
    
    static func purge() {
        let keys = UserDefaultsKey.allCases
        keys.forEach {
            let excluded = UserDefaultsKey.excludedCases.contains($0)
            if excluded {
                print("Excluded case: \($0.value)")
            } else {
                UserDefaultManager.shared.remove(for: $0)
            }
        }
    }
}

enum UserDefaultsKey: String, CaseIterable {
    
    case currentLoggedinBranch = "currentLoggedinBranch"
    case username = "login"
    case locationCode = "location_code"
    case companyName = "company name"
    case companyID = "Current company id"
    case lastLoginDate = "lastLoginDate"
    case vat = "VAT"
    case vatPercentage = "vatperc"
    case admin
    case serialNumber
    case redeamEnabled
    case issueEnabled
    // no need to purge
    case merchantID
    case merchantName
    case lastUpdateNotification
    case theme = "Theme"
    case ipAddress = "ip"
    case voidKey = "void"
    
    // Helper
    static var excludedCases: [UserDefaultsKeys] = [ .voidKey, .ipAddress, .merchantID, .merchantName, .lastUpdateNotification, .theme]
    
    var value : String {
        return self.rawValue
    }
    
}

@amrangry
Copy link
Author

amrangry commented May 5, 2020

// Genaric is much easier to handle in code
    func set<T>(_ obj: T, for key: UserDefaultsKey) {
        self.userDefaults?.set(object, forKey: key.value)
        self.userDefaults?.synchronize()
    }
    // Genaric is much easier to handle in code
    func get<T>(for key: UserDefaultsKey) -> T? {
        let result = self.userDefaults?.object(forKey: key.value) as? T
        return result
    }

I agree with you, thanks for your suggestion, ima going to modify and posted here again

@barangngr
Copy link

barangngr commented Jul 4, 2023

There may be a small typo that has been overlooked.
self.userDefaults?.set(object, forKey: key.value)

to

self.userDefaults?.set(obj, forKey: key.value)

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