用来做简单数据存储的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
,在存储和读取数据时调动的set
和get
方法也可以交给目标属性默认的set
和get
方法去做。
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
缓存到内存中,下次再访问时,如果内存中命中就直接访问,如果未命中再从文件中载入。它还会时不时调用同步方法来保证内存与文件中的数据的一致性,有时在写入一个值后也最好调用下这个方法来保证数据真正写入文件。