上一节已经讲解了如何使用NSKeyedArchiver将自定义的对象保存到文件中。但个人觉得每次保存一个自定义对象到文件中都必须执行如下步骤:
1、遵循 NSCoding 协议
2、实现下面两个方法
- (void)encodeWithCoder:(NSCoder *)encoder //归档方法
- (id)initWithCoder:(NSCoder *)decoder // 解档方法
3、在上面两个方法中编写归档属性和解档属性的代码。
上面三步对于初学者来说,敲多几次就熟了,每次都敲的话就是浪费时间,浪费生命。所以我自定义了一个类,将上面三步都封装起来。以后要想使用NSKeyedArchiver将一个对象保存都文件中,只需要继承下面的类,然后调用一个方法即可完成保存操作。
// 头文件
#import <Foundation/Foundation.h>
@interface PKXObject : NSObject<NSCoding>
/** 将模型对象保存到指定的路径:绝对路径 */
-(BOOL)saveToFile:(NSString *)filePath;
/** 从指定的文件路径读取模型对象 */
+(id)objectFromFilePath:(NSString *)filePath;
/** 将模型对象保存到默认的文件中(默认文件名:t_类名) */
-(BOOL)save;
/** 从默认文件(默认文件名:t_类名)中获得模型对象*/
+(id)objectWithoutFilePath;
@end
</pre><pre name="code" class="objc"><pre name="code" class="objc">//.m 文件
#import "PKXObject.h"
#import <objc/runtime.h>
#define CZFilePath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"t_%@",[self class]]]
@implementation PKXObject
#pragma mark - 保存对象到文件/从文件中读取对象
/** 将模型对象保存到指定的路径:绝对路径 */
-(BOOL)saveToFile:(NSString *)filePath{
if (filePath == nil || filePath.length == 0)filePath = CZFilePath;
return [NSKeyedArchiver archiveRootObject:self toFile:filePath];
}
/** 将模型对象保存到默认的文件中(默认文件名:t_类名) */
-(BOOL)save{
return [self saveToFile:nil];
}
/** 从指定的文件路径读取模型对象 */
+(id)objectFromFilePath:(NSString *)filePath {
if (filePath == nil || filePath.length == 0)filePath = CZFilePath;
return [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
}
/** 从默认文件(默认文件名:t_类名)中获得模型对象*/
+(id)objectWithoutFilePath{
return [self objectFromFilePath:nil];
}
#pragma mark - NSCoding协议
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (self) {
Class class = [self class];
while (class != [NSObject class]) {
unsigned int count = 0;
// 1.获取类成员变量列表,count为类成员变量数量
Ivar *vars = class_copyIvarList(class, &count);
for (int index = 0; index < count; index ++) {
// 2.根据索引获得指定位置的成员变量
Ivar var = vars[index];
// 3.获得成员变量名
const char *name = ivar_getName(var);
// 4.成员变量名转化成oc字符串
NSString *varName = [NSString stringWithUTF8String:name];
// 5.成员变量类型
const char *type = ivar_getTypeEncoding(var);
// 5.1 成员变量类型转换成 oc 字符串
NSString *varType = [NSString stringWithUTF8String:type];
if ([varType isEqualToString:@"i"]) { // 整形
NSInteger value = [decoder decodeIntegerForKey:varName];
[self setValue:[NSNumber numberWithInteger:value] forKey:varName];
} else if([varType isEqualToString:@"f"]) { // 单精度浮点型
CGFloat value = [decoder decodeFloatForKey:varName];
[self setValue:[NSNumber numberWithFloat:value] forKey:varName];
} else if([varType isEqualToString:@"d"]) { // 双精度浮点型
double value = [decoder decodeDoubleForKey:varName];
[self setValue:[NSNumber numberWithDouble:value] forKey:varName];
} else if([varType isEqualToString:@"c"]) { // BOOL 类型
BOOL value = [decoder decodeBoolForKey:varName];
[self setValue:[NSNumber numberWithBool:value] forKey:varName];
} else if ([varType containsString:@"@"]) { // OC 对象
[self setValue:[decoder decodeObjectForKey:varName] forKey:varName];
}
}
// 6.释放指针
free(vars);
// 7.获得父类
class = class_getSuperclass(class);
}
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder {
unsigned int count = 0;
Class class = [self class];
while (class != [NSObject class]) {
// 1.获取类成员变量列表,count为类成员变量数量
Ivar *vars = class_copyIvarList(class, &count);
for (int index = 0; index < count; index ++) {
// 2.根据索引获得指定位置的成员变量
Ivar var = vars[index];
// 3.获得成员变量名
const char *name = ivar_getName(var);
// 4.成员变量名转化成oc字符串
NSString *varName = [NSString stringWithUTF8String:name];
// 5.成员变量类型
const char *type = ivar_getTypeEncoding(var);
// 5.1 成员变量类型转换成 oc 字符串
NSString *varType = [NSString stringWithUTF8String:type];
// 6.获得成员变量的值
id value = [self valueForKey:varName];
if (value == nil) continue;
if ([varType isEqualToString:@"i"]) { // 整形
[encoder encodeInteger:[value integerValue] forKey:varName];
} else if([varType isEqualToString:@"f"]) { // 单精度浮点型
[encoder encodeFloat:[value floatValue] forKey:varName];
} else if([varType isEqualToString:@"d"]) { // 双精度浮点型
[encoder encodeDouble:[value doubleValue] forKey:varName];
} else if([varType isEqualToString:@"c"]) { // BOOL 类型
[encoder encodeBool:[value boolValue] forKey:varName];
} else if ([varType containsString:@"@"]) { // OC 对象
[encoder encodeObject:value forKey:varName];
}
}
// 7.释放指针
free(vars);
// 8.获得父类
class = class_getSuperclass(class);
}
}
@end