官网文档:NSUserDufaultClass Reference
关于偏好设置:AboutPreferences and Settings
UserDefualts是一种便利的,通过key-value的一种持久化方案。
常用于存储应用相关的用户设置,自定义个性化设置,首次使用引导等。适合于简单数据小量储存,涉及记住密码和隐私,建议采用keyChain。
偏好设置以plist文件形式存储在应用沙盒的Preferences目录下,文件名:bundleId.plist
对于 Swift 来说 UserDefualt只支持的基本数据类型,(对于OC 存储基础对象数据)。
基本数据类型:Int、Float、Double、Bool
基本对象和数据结构:String、URL、Dictionary、Array
支持转为Data类型的自定义类型:Data、支持 NSCoding/Codable 可以转化为 NSData
Tip: 除了存储自定义key-value 外,偏好设置自身存在一些设置值,比如应用语言AppleLanguages
UserDefaults 基本使用
如下示例
使用UserDefaults的standerd来记录用户信息,判断是否为第一次登陆。进行自动登陆操作
扩展 UserDefaults 来避免使用硬编码
针对保存的 key, 我们应该避免通过字符串硬编码,可以通过扩展定义方式,减少拼写错误,充分利用编辑器提示检查功能。
extension UserDefaults {
enum Key {
static let username = "username"
static let password = "password"
static let rememberPassword = "rememberPassword"
/// 是否展示用户引导
static let showGuide = "showGuide"
}
}
增删改查
// 数据持久化值NSUserDefault
func useUserDefault() {
let username = "username"
let password = 188888666
let rememberPassword: Bool = true // 记住密码
let firstLog: Bool = false // 非首次登录(如果是首次登录可以产生引导界面)
// 设置数据到沙盒中
let userDefault = UserDefaults.standard
// 为 key 注册初始值。
// userDefault.register(defaults: <#T##[String : Any]#>)
userDefault.set(username, forKey: UserDefaults.Key.username)
userDefault.set(password, forKey: UserDefaults.Key.password)
userDefault.set(rememberPassword, forKey: UserDefaults.Key.rememberPassword)
userDefault.set(firstLog, forKey: UserDefaults.Key.showGuide)
// 设置同步,会立即保存到磁盘
//userDefault.synchronize()
// 取数据
print("用户名:", userDefault.value(forKey: UserDefaults.Key.username))
print("密码为:", userDefault.integer(forKey: UserDefaults.Key.password))
// 删除数据
UserDefaults.standard.removeObject(forKey: "password")
print("密码为:", UserDefaults.standard.integer(forKey: UserDefaults.Key.password)) // 输出结果 密码为:0
}
synchronize()
方法主要用于同步到磁盘,不过现在可以不用写了。
官方提示 -synchronize is deprecated and will be marked with the API_DEPRECATED macro in a future release.
UserDefaults保存自定义类型
自定义类型默认是不支持 UserDefaults, 但是可以存 Data, 所以我们可以将自定义类型转化为 Data,主要有两种方式
-
实现 Swift自带的 Codable【推荐】
-
实行 NSCoding/NSSecureCoding[区别]
然后将其转化为 Data 保存。
自定义类实现 Codable
extension UserDefaults {
/// 遵守Codable协议的set方法
///
/// - Parameters:
/// - object: 泛型的对象
/// - key: 键
/// - encoder: 序列化器
public func setCodableObject<T: Codable>(_ object: T, forKey key: String, usingEncoder encoder: JSONEncoder = JSONEncoder()) {
let data = try? encoder.encode(object)
set(data, forKey: key)
}
/// 遵守Codable协议的get方法
///
/// - Parameters:
/// - type: 泛型的类型
/// - key: 键
/// - decoder: 反序列器
/// - Returns: 可选类型的泛型的类型对象
public func getCodableObject<T: Codable>(_ type: T.Type, with key: String, usingDecoder decoder: JSONDecoder = JSONDecoder()) -> T? {
guard let data = value(forKey: key) as? Data else { return nil }
return try? decoder.decode(type.self, from: data)
}
}
自定义类实现 NSCoding
NSCoding 是 Objective-C 转化对象为 Data的方式,且支持 class。
- 定义类,实现 NSCoding 协议和方法
class Class: NSObject, NSCoding {
let className: String
let roomName: String
let cellNumber: Int
init(className: String, roomName: String, cellNumber: Int) {
self.className = className
self.roomName = roomName
self.cellNumber = cellNumber
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.className, forKey: "name")
aCoder.encode(self.roomName, forKey: "room")
aCoder.encode(self.cellNumber, forKey: "number")
}
required init?(coder aDecoder: NSCoder) {
self.className = aDecoder.decodeObject(forKey: "name") as! String
self.roomName = aDecoder.decodeObject(forKey: "room") as! String
self.cellNumber = aDecoder.decodeInteger(forKey: "number")
}
}
- 通过 NSKeyedArchiver 转为 Data
let classA = Class(className: "a", roomName: "a", cellNumber: 1)
let classAData = try NSKeyedArchiver.archivedData(withRootObject: classA, requiringSecureCoding: false) // 是否使用 SecureCoding
-
将 Data 存在 UserDefaults 中
-
取出 UserDefauls 对象Data, 通过 NSKeyedUnarchiver 转为对象。
UserDefaults 默认值
在通过 key取值的时候,如果之前没有存过,会是什么默认了。
未存储初始值
- 基本数据类型
类型 | 默认值 |
---|---|
integer | 0 |
double/float | 0.0 |
bool | false |
let userdefaultStandard = UserDefaults.standard
let defaultBool = userdefaultStandard.bool(forKey: "bool") // false
let defaultInt = userdefaultStandard.integer(forKey: "int") // 0
let defaultDouble = userdefaultStandard.double(forKey: "double") // 0.0
let defaultDouble = userdefaultStandard.float(forKey: "float") // 0.0
- 基本对象和数据结构,入 String、 URL、Array、Dictionary默认为nil
- 自定义 Data对象也为 nil
UserDefaults 设置默认值方式
为了保证程序的稳健型,和减少判断。我们需要注意 UserDefaults 的默认值,可以通过设置默认值来较少意外。
使用之前设置一遍值
为了保证默认值情况,可以在取值之前设置一遍默认值,这种方式是最简单便利的。
通过 register 字典赋初始值
通过 UserDefaults 的 register 方法添加默认值,而且当这个值为nil或者没设置过有效。
let userDefaults = UserDefaults.standard
userDefaults.register(
defaults: [
UserDefaults.Key.showGuide: false
]
)
可通过Scheme 的 Run Argments 参数来指定默认值。
如下图,为 UserDefaults 添加 hasSeenAppIntroduction 的 key 值为 0
像字典一样存取
字典可以通过 dic[key]
来存取值,其实可以通过扩展和 swift下标,也能实现下标 存取
extension UserDefaults {
/// 针对Any?
public subscript(key: String) -> Any? {
get {
return object(forKey: key)
}
set {
set(newValue, forKey: key)
}
}
// 扩展其他类型
}