【iOS数据持久化】偏好设置(UserDefaults)

官网文档: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 基本使用

如下示例

扫描二维码关注公众号,回复: 14878816 查看本文章

使用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,主要有两种方式

  1. 实现 Swift自带的 Codable【推荐】

  2. 实行 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。

  1. 定义类,实现 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")
    }
}
  1. 通过 NSKeyedArchiver 转为 Data
let classA  = Class(className: "a", roomName: "a", cellNumber: 1)
let classAData = try NSKeyedArchiver.archivedData(withRootObject: classA, requiringSecureCoding: false) // 是否使用 SecureCoding
  1. 将 Data 存在 UserDefaults 中

  2. 取出 UserDefauls 对象Data, 通过 NSKeyedUnarchiver 转为对象。

UserDefaults 默认值

在通过 key取值的时候,如果之前没有存过,会是什么默认了。

未存储初始值

  1. 基本数据类型
类型 默认值
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
  1. 基本对象和数据结构,入 String、 URL、Array、Dictionary默认为nil
  2. 自定义 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

img

像字典一样存取

字典可以通过 dic[key]来存取值,其实可以通过扩展和 swift下标,也能实现下标 存取

extension UserDefaults {
    
    

    /// 针对Any?
    public subscript(key: String) -> Any? {
    
    
        get {
    
    
            return object(forKey: key)
        }
        set {
    
    
            set(newValue, forKey: key)
        }
    }
    // 扩展其他类型
}

猜你喜欢

转载自blog.csdn.net/qq_14920635/article/details/120782353