請看具體實現(xiàn),注釋詳細. 覺得用的上的朋友麻煩點個贊.自己寫的實用小工具.
使用的時候直接繼承自BaseModel 就可以了
//字典轉(zhuǎn)模型
let model = BaseModel.init(dict: dic)
//一句話快速歸檔,括號內(nèi)輸入單個模型或者模型數(shù)組
model.archiverWithRootObject([model1, model2, model3])
//一句話快速解檔.無論你存入的是單個對象還是數(shù)組
let modelArray = account.unarchiver()
一句話歸檔效果,數(shù)據(jù)是本人的微博信息.
怎么樣?是不是非常的cool,以下是兩個語言版本的具體實現(xiàn),希望用的同時能認真看注釋,理解其中簡單的原理.
OC版本
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
@implementation BaseModel
- (instancetype)initWithDic:(NSDictionary *)dic
{
if (self = [super init]) {
[self setValuesForKeysWithDictionary:dic];
}
return self;
}
#pragma mark 數(shù)據(jù)持久化
- (void)encodeWithCoder:(NSCoder *)aCoder
{
//獲取當前類的所有屬性名稱
unsigned int outCount, i;
objc_property_t *properties =class_copyPropertyList([self class], &outCount);
//遍歷所有的屬性名稱
for (i = 0; i < outCount; i++)
{
//取出單個屬性名稱
objc_property_t property = properties[i];
const char* char_f = property_getName(property);
//轉(zhuǎn)換成OC串
NSString *propertyName = [NSString stringWithUTF8String:char_f];
//KVC取值
id propertyValue = [self valueForKey:(NSString *)propertyName];
//如果取出來有值 則歸檔
if (propertyValue)
{
[aCoder encodeObject:propertyValue forKey:propertyName];
}
}
}
- (id)initWithCoder:(NSCoder *)aCoder
{
self = [super init];
if (self)
{
//取出所有的屬性名稱
unsigned int outCount, i;
objc_property_t *properties =class_copyPropertyList([self class], &outCount);
//遍歷屬性
for (i = 0; i<outCount; i++)
{
//取出單個屬性
objc_property_t property = properties[i];
const char* char_f = property_getName(property);
NSString *propertyName = [NSString stringWithUTF8String:char_f];
//KVC賦值
[self setValue:[aCoder decodeObjectForKey:propertyName] forKey:propertyName];
}
}
return self;
}
//存檔
+ (void)archiverWithRootObject:(id)rootObject{
NSString *fileName = NSStringFromClass([self class]);
[NSKeyedArchiver archiveRootObject:rootObject toFile:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileName]];
}
//解檔
+ (id)unarchiver{
NSString *fileName = NSStringFromClass([self class]);
return [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileName]];
}
@end
Swift版本
//
// BaseModel.swift
// WeiboSwift
//
// Created by 曾凡怡 on 2017/1/5.
// Copyright ? 2017年 曾凡怡. All rights reserved.
//
import UIKit
class BaseModel: NSObject,NSCoding {
init(dict : [String : Any]) {
super.init()
setValuesForKeys(dict)
}
required init?(coder aDecoder: NSCoder) {
//先初始化
super.init()
//獲取當前類的所有屬性名
let nameList = getPropertyNameList()
//進行解檔
for key in nameList{
//從aDecoder中取值
let value = aDecoder.decodeObject(forKey: key)
//賦值給自己
setValue(value, forKey: key)
}
}
func encode(with aCoder: NSCoder) {
//獲取當前類的所有屬性名
let nameList = getPropertyNameList()
//進行歸檔
for key in nameList{
//KVC取值
if let value = value(forKey: key){
////歸檔.此處注意歸檔的方法中要使用帶 forKey參數(shù)的
aCoder.encode(value, forKey: key)
}
}
}
func getPropertyNameList () -> [String]{
//保存屬性的個數(shù)
var outCount : UInt32 = 0
//保存屬性名稱的數(shù)組
var list : [String] = []
//獲取屬性集合
let property = class_copyPropertyList(type(of:self), &outCount)
//解包
guard let propertyList = property else {
return list
}
for i in 0 ..< Int(outCount){
//取出單個屬性
let property = propertyList[i]
//獲取屬性的名字
guard let char_f = property_getName(property) else{
continue
}
//轉(zhuǎn)換為String
if let key = NSString(cString: char_f, encoding: String.Encoding.utf8.rawValue) as? String {
//添加到數(shù)組
list.append(key)
}
}
return list
}
func archiverWithRootObject(_ rootObjcet : Any){
let filePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last!
let fileName = NSStringFromClass(self.classForCoder) as String
let savePath = filePath + "/" + fileName + ".plist"
//歸檔
NSKeyedArchiver.archiveRootObject(rootObjcet, toFile:savePath)
}
func unarchiver()->Any?{
let filePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).last!
let fileName = NSStringFromClass(self.classForCoder) as String
let savePath = filePath + "/" + fileName + ".plist"
//解檔出來的元素
return NSKeyedUnarchiver.unarchiveObject(withFile: savePath)
}
}
巨坑
Swift的巨坑!!!...哭了一下午,一直在解檔崩潰.最后發(fā)現(xiàn)問題在歸檔.
//下面兩種歸檔的方法要注意了.不要使用第一種歸檔.
~~aCoder.encode(object: Any?)~~ 警告,不要使用
//而第二種方法因為第一個參數(shù)沒有外部參數(shù),很難打出來.
aCoder.encode(objv: Any?, forKey: String)
//輸入aCoder.encodeforkey 來查找這個方法