swift 简化使用UserDefaults,UserDefaults使用优化

用来做简单数据存储的Preference在我们的日常开发中使用的还是比较多的,但使用起来总感觉不那么方便。比如说需要去手动管理key,之前是这样做的。

public enum UserDefaultsKey: String {
    case keyOne
    case keyTwo
}

extension UserDefaults {
    /// 存储
    public final class func set(_ value: Any, forKey: UserDefaultsKey) {
        UserDefaults.standard.set(value, forKey: forKey.rawValue)
    }
    /// 读取
    public final class func getString(forKey: UserDefaultsKey) -> String? {
        return UserDefaults.standard.string(forKey: forKey.rawValue)
    }
    public final class func getBool(forKey: UserDefaultsKey) -> Bool? {
        return UserDefaults.standard.bool(forKey: forKey.rawValue)
    }
}

// 存储数据
UserDefaults.set(true, forKey: .keyOne)
// 读取数据        
UserDefaults.getBool(forKey: .keyOne)

  或者是这样做的

var AuthToken:String?{
        set{
            let userData:UserDefaults=UserDefaults.standard
            userData.set(newValue, forKey: "AccountInfo_AuthToken")
        }
        get{
            let userData:UserDefaults=UserDefaults.standard
            return userData.object(forKey: "AccountInfo_AuthToken") as? String
        }
}

  

我们可以通过使用 #function 避免手动管理key,在存储和读取数据时调动的setget方法也可以交给目标属性默认的setget方法去做。

extension UserDefaults {
    /// 通过下标使用枚举
    subscript<T: RawRepresentable>(key: String) -> T? {
        get {
            if let rawValue = value(forKey: key) as? T.RawValue {
                return T(rawValue: rawValue)
            }
            return nil
        }
        set { set(newValue?.rawValue, forKey: key) }
    }
    
    subscript<T>(key: String) -> T? {
        get { return value(forKey: key) as? T }
        set { set(newValue, forKey: key) }
    }
}

struct Preference {
    /// bool
    static var isFirstLogin: Bool {
        get { return UserDefaults.standard[#function] ?? false }
        set { UserDefaults.standard[#function] = newValue }
    }

    /// string
    static var userName: String {
        get { return UserDefaults.standard[#function] ?? "yourDefaultValue" }
        set { UserDefaults.standard[#function] = newValue }
    }

    /// enum
    static var appTheme: Theme {
        get { return UserDefaults.standard[#function] ?? .light }
        set { UserDefaults.standard[#function] = newValue }
    }
    /// 测试服跟正式服之间的切换(默认正式服)
    static var serverUrl: ServerUrlType {
        get { return UserDefaults.standard[#function] ?? .distributeServer }
        set { UserDefaults.standard[#function] = newValue }
    }
}

enum Theme: Int {
    case light
    case dark
    case blue
}

enum ServerUrlType: String {
    case developServer = "url: developServer" // 测试服
    case distributeServer = "url: distributeServer" // 正式服
}

// 存储数据
Preference.isFirstLogin = true
Preference.appTheme = .dark
Preference.serverUrl = .developServer 

// 读取数据
Preference.isFirstLogin // true
Preference.appTheme == .dark // true 
Preference.serverUrl.rawValue // url: developServer

在测试环节经常需要在测试服和正式服来回切换,为了避免老是打包,我们可以利用UserDefaults去更改服务器地址,在适当的位置(可以是个测试页面)加个UISwitch,然后设置serverUrl的值。

UserDefaults有性能问题吗?

UserDefaults是带缓存的。它会把访问到的key缓存到内存中,下次再访问时,如果内存中命中就直接访问,如果未命中再从文件中载入。它还会时不时调用同步方法来保证内存与文件中的数据的一致性,有时在写入一个值后也最好调用下这个方法来保证数据真正写入文件。

来源:SwiftTips记录iOS开发中的一些知识点