Swift4.2如何优雅的使用归档解档
2018-10-28 本文已影响13人
船长_
Swift4 之前归档解档model写法
@objc class UserInfo: NSObject, NSCoding {
var name: String
var age: Int
var email: String
override init() {
super.init()
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(age, forKey: "age")
aCoder.encode(email, forKey: "email")
}
required init?(coder aDecoder: NSCoder) {
name = aDecoder.decodeObject(forKey: "name") as? String
age = aDecoder.decodeObject(forKey: "age") as? Int
email = aDecoder.decodeObject(forKey: "email") as? String
}
}
Swift4 之后只需要你的model
遵守Codable
协议
class UserModel: Codable {
var name: String
var age: Int
var email: String
}
存储对象示例
let data = try PropertyListEncoder().encode(object)
let success = NSKeyedArchiver.archiveRootObject(data, toFile: path)
获取对象示例
let data = NSKeyedUnarchiver.unarchiveObject(withFile: path)
封装了一个工具类单例,根据key来存储不同的对象
具体代码实现
public class DXCacheManager {
private var directoryUrl:URL?
private var fileManager : FileManager{
return FileManager.default
}
private var cacheQueue = DispatchQueue.init(label: "com.nikkscache.dev.cacheQueue")
public static var sharedInstance = DXCacheManager.init(cacheName: Bundle.main.infoDictionary?["TargetName"] as? String ?? "MyAppCache")
//MARK:- Initializers
/// Private class initializer
private init() {}
/// This initializer method will use ~/Library/Caches/com.nikkscache.dev/targetName to save data
///
/// - Parameter cacheName: Name of the cache (by default it is 'TargetName')
private init(cacheName: String) {
if let cacheDirectory = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last {
let dir = cacheDirectory + "/com.nikkscache.dev/" + cacheName
directoryUrl = URL.init(fileURLWithPath: dir)
if fileManager.fileExists(atPath: dir) == false{
do{
try fileManager.createDirectory(atPath: dir, withIntermediateDirectories: true, attributes: nil)
}catch{}
}
}
}
//MARK:- Adding / Removing Cached Object
/// This method will write Object of specified type to a particular key in cache directory
///
/// - Parameters:
/// - object: Object to be cached
/// - key: Identifier in cache for object
public func setObject<T: Codable>(_ object: T,forKey key:String) {
cacheQueue.async { [weak self] in
//dispatch asynchronously on cacheQueue
guard let path = self?.pathForKey(key) else{
print("File at path for key : \(key) not found")
return
}
do{
let data = try PropertyListEncoder().encode(object)
let success = NSKeyedArchiver.archiveRootObject(data, toFile: path)
var fileUrl = URL.init(fileURLWithPath: path)
self?.excludeFromBackup(fileUrl: &fileUrl)
print(success ? "data saved to cache SUCCESSFULLY" : "data caching FAILED")
}catch{
print("data caching FAILED")
}
}
}
/// This method will remove Object corresponding to specified key
///
/// - Parameter key: Identifier in cache for object
func removeObjectForKey(_ key: String) {
//dispatch asynchronously on cacheQueue
cacheQueue.sync { [weak self] in
guard let path = self?.pathForKey(key) else{
print("File at path for key : \(key) not found")
return
}
do {
try fileManager.removeItem(atPath: path)
print("cached data for key \(key) removed SUCCESSFULLY")
} catch {
print("FAILED removing cachced data for key \(key)")
}
}
}
public func removeAllObjects(){
cacheQueue.async { [weak self] in
guard let `self` = self else{ return }
guard let directoryUrls = self.directoryUrl else{ return }
do {
try self.fileManager.contentsOfDirectory(at: directoryUrls, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions.skipsHiddenFiles).forEach{
do{
try self.fileManager.removeItem(atPath: $0.path)
print("cached data item removed SUCCESSFULLY")
}catch{
print("FAILED removing all cached data")
}
}
}catch{
print("FAILED removing all cached data")
}
}
}
//MARK: - Fetching cached object
/// This method is used to retrieve value from cache for specified key
///
/// - Parameters:
/// - key: Identifier in cache for object
/// - completionHandler: For handling completion state of fetch operation
public func getObjectForKey<T: Codable>(_ key: String, completionHandler: @escaping (T?)->()) {
cacheQueue.async { [weak self] in
guard let path = self?.pathForKey(key) else{
print("File at path for key : \(key) not found")
return
}
guard let data = NSKeyedUnarchiver.unarchiveObject(withFile: path) as? Data else{
print("ERROR data retriving from cache")
DispatchQueue.main.async {
completionHandler(nil)
}
return
}
do {
let object = try PropertyListDecoder().decode(T.self, from: data)
print("data retriving SUCCESSFULLY from cache")
DispatchQueue.main.async {
completionHandler(object)
}
}catch{
print("ERROR data retriving from cache")
DispatchQueue.main.async {
completionHandler(nil)
}
}
}
}
//MARK: - Private Methods
private func pathForKey(_ key: String)->String?{
return directoryUrl?.appendingPathComponent(key).path
}
/// This method is used beacuse it is required as per App Store Review Guidelines/ iOS Data Storage Guidelines to exculude files from being backedup on iCloud
///
/// - Parameter fileUrl: filePath url for file to be excluded from backup
/// - Returns: <#return value description#>
@discardableResult
private func excludeFromBackup(fileUrl: inout URL) ->Bool {
if fileManager.fileExists(atPath: fileUrl.path) {
fileUrl.setTemporaryResourceValue(true, forKey: URLResourceKey.isExcludedFromBackupKey)
return true
}
return false
}
}
简单解析
- 1.使用了单例
- 2.数据储存在
FileManager.SearchPathDirectory.cachesDirectory
文件中新建了文件 - 3.数据储存和获取的方法使用了泛型参数,并做了相关约束
- 4.使用异步方法进行了数据存储和获取
使用示例
存储数据示例
@objc func storeSingleDataAction() {
let user = UserModel(name: "Harvey", age: 18, email: "yaozuopan@icloud.com")
DXCacheManager.sharedInstance.setObject(user, forKey: userModelKey)
}
@objc func storeComplexDataAction() {
let group = Department(name: "软件部", id: 889)
let user1 = UserModel(name: "Harvey", age: 18, email: "Harvey@icloud.com")
let user2 = UserModel(name: "Jojo", age: 25, email: "Jojo@icloud.com")
user2.qq = "863223764"
group.member = [user1, user2]
DXCacheManager.sharedInstance.setObject(group, forKey: departmentKey)
}
获取数据示例
@objc func fetchSingleDataAction() {
DXCacheManager.sharedInstance.getObjectForKey(userModelKey) { (result : UserModel?) in
guard let item = result else{
print("获取失败了")
return
}
print("name=\(item.name),age=\(item.age),email=\(item.email),qq=\(String(describing: item.qq))")
}
}
// 获取嵌套model
@objc func fetchComplexDataAction() {
DXCacheManager.sharedInstance.getObjectForKey(departmentKey) { (result : Department?) in
guard let model = result else{
print("获取失败了")
return
}
for item in model.member {
print("name=\(item.name),age=\(item.age),email=\(item.email),qq=\(item.qq ?? "无")")
}
}
}
移除数据示例
@objc func removeSingleDataAction() {
DXCacheManager.sharedInstance.removeObjectForKey(userModelKey)
}
@objc func removeAllDataAction() {
DXCacheManager.sharedInstance.removeAllObjects()
}