本文章包含以下几个知识点,
一,KeychainAccess存,读,删
二,model序列化和反序列化的实现
注意事项
model序列化需要添加@objcMembers,否则class_copyPropertyList遍历的属性数组为空
以下为相关代码:
XLUserInfoTool
import UIKit
import KeychainAccess
let user_path = "user.db"
class XLUserInfoTool: NSObject {
var userPath = FileManager.getCurrentStoreagePath(user_path)
static let shareUserInfoTool = XLUserInfoTool()
var userInfo: userInfoModel!
override init() {
super.init()
if FileManager.checkFileIsExist(userPath) == true {
userInfo = NSKeyedUnarchiver.unarchiveObject(withFile: userPath) as? userInfoModel
loginStatus = (userInfo?.id != nil)
}
}
var loginStatus: Bool? {
didSet {
if loginStatus == false {
XLLogout()
userInfo = UserInfoModel()
}
loginStatusChange()
}
}
/// 保存用户
public func saveUser() {
guard let user = userInfo else { return }
DispatchQueue.global().async {
let suc = NSKeyedArchiver.archiveRootObject(user, toFile: self.userPath)
if suc == false {
NSLog(message:"保存user失败")
}
}
}
///清除用户
fileprivate func clearUser() {
guard userInfo != nil else { return }
let suc = FileManager.removePath(self.userPath)
if suc == false {
NSLog(message:"用户清除失败")
}
}
///退出登录
func XLLogout() {
RootVCApplicationService.init().switchToRootViewControllerByDestinationType(type: .homeLogin)
}
///登录状态变更
func loginStatusChange() {
}
}
userInfoModel
@objcMembers class userInfoModel: : NSObject,HandyJSON,NSCoding,CodeArchive {
var username : String?
var token : String?
var id : String?
required override init() {
super.init()
}
required init?(coder aDecoder: NSCoder) {
super.init()
codeDecoder(coder: aDecoder)
}
func encode(with aCoder: NSCoder) {
codeEncoder(with: aCoder)
}
}
NSObject+Extension.swift
import Foundation
extension NSObject {
protocol CodeArchive {
func codeDecoder(coder aDecoder: NSCoder)
func codeEncoder(with aCoder: NSCoder)
}
extension CodeArchive where Self: NSObject {
func codeDecoder(coder aDecoder: NSCoder) {
// 这个类型可以使用CUnsignedInt,对应Swift中的UInt32
var count: UInt32 = 0
let properties = class_copyPropertyList(self.classForCoder, &count)
var propertyNames: [String] = []
// Swift中类型是严格检查的,必须转换成同一类型
for i in 0 ..< Int(count) {
// UnsafeMutablePointer<objc_property_t>是
// 可变指针,因此properties就是类似数组一样,可以
// 通过下标获取
let property = properties![i]
let name = property_getName(property)
// 这里还得转换成字符串
let propertyName = String(cString: name)
propertyNames.append(propertyName)
if let value = aDecoder.decodeObject(forKey: propertyName) {
setValue(value, forKey: propertyName)
}
}
// 释放内存,否则C语言的指针很容易成野指针的
free(properties)
}
func codeEncoder(with aCoder: NSCoder) {
// 这个类型可以使用CUnsignedInt,对应Swift中的UInt32
var count: UInt32 = 0
NSLog(message:self.classForCoder)
let properties = class_copyPropertyList(self.classForCoder, &count)
for i in 0 ..< Int(count) {
// 获取属性名称
let property = properties![i]
let name = property_getName(property)
let propertyName = String(cString: name)
if (!propertyName.isEmpty) {
// 获取Value数据
let propertyValue = self.value(forKey: propertyName)
if let value = propertyValue {
aCoder.encode(value, forKey: propertyName)
}
}
}
}
}