利用运行时实现归档、解档,并将其封装成宏
- 继承
NSObject
并遵守NSCoding
协议,创建一个类
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCoding>
@property(nonatomic, copy) NSString *name;
@property(nonatomic, assign) NSInteger age;
@end
- 在
.m
中NSCoding
协议的方法,需要引入运行时头文件#import <objc/runtime.h>
#import "Person.h"
#import <objc/runtime.h>
@implementation Person
- (void)encodeWithCoder:(NSCoder *)encoder{
unsigned int count = 0;
Ivar * ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i++) {
// 取出i位置对应的成员变量
Ivar ivar = ivars[i];
// 查看成员变量
const char * name = ivar_getName(ivar);
// 归档
NSString * key = [NSString stringWithUTF8String:name];
id value = [self valueForKey:key];
[encoder encodeObject:value forKey:key];
}
// 释放内存
free(ivars);
}
- (instancetype)initWithCoder:(NSCoder *)decoder{
if (self = [super init]) {
unsigned int count = 0;
Ivar * ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i++) {
// 取出i位置对应的成员变量
Ivar ivar = ivars[i];
// 查看成员变量
const char * name = ivar_getName(ivar);
// 解档
NSString * key = [NSString stringWithUTF8String:name];
id value = [decoder decodeObjectForKey:key];
// 设置到成员变量身上
[self setValue:value forKey:key];
}
// 释放内存
free(ivars);
}
return self;
}
@end
- 归档解档测试
- (void)viewDidLoad {
[super viewDidLoad];
Person * p = [[Person alloc] init];
p.name = @"Tom";
p.age = 28;
// 归档路径
NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
NSString * filePath = [path stringByAppendingPathComponent:@"archiver_person"];
// 归档
BOOL result = [NSKeyedArchiver archiveRootObject:p toFile:filePath];
if (result) {
NSLog(@"归档成功");
}else{
NSLog(@"归档失败");
}
// 解档
Person * p1 = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"%@", p1.name);
}
- 新建头文件
Archiver.h
, 将Person.m
中NSCoding
协议的方法写成宏,以便于多处调用,而不需重相同的工作,代码如下:
#define ArchiverM(className)\
- (void)encodeWithCoder:(NSCoder *)encoder{\
unsigned int count = 0;\
Ivar * ivars = class_copyIvarList([className class], &count);\
for (int i = 0; i < count; i++) {\
Ivar ivar = ivars[i];\
const char * name = ivar_getName(ivar);\
NSString * key = [NSString stringWithUTF8String:name];\
id value = [self valueForKey:key];\
[encoder encodeObject:value forKey:key];\
}\
free(ivars);\
}\
- (instancetype)initWithCoder:(NSCoder *)decoder{\
if (self = [super init]) {\
unsigned int count = 0;\
Ivar * ivars = class_copyIvarList([className class], &count);\
for (int i = 0; i < count; i++) {\
Ivar ivar = ivars[i];\
const char * name = ivar_getName(ivar);\
NSString * key = [NSString stringWithUTF8String:name];\
id value = [decoder decodeObjectForKey:key];\
[self setValue:value forKey:key];\
}\
free(ivars);\
}\
return self;\
}
- 宏的使用,在需要归/解档的类的
.m
文件中引入#import "Archiver.h"
,并调用宏ArchiverM(类名)
#import "Person.h"
#import <objc/runtime.h>
#import "Archiver.h"
@implementation Person
ArchiverM(Person)
//- (void)encodeWithCoder:(NSCoder *)encoder{
// unsigned int count = 0;
// Ivar * ivars = class_copyIvarList([Person class], &count);
//
// for (int i = 0; i < count; i++) {
// // 取出i位置对应的成员变量
// Ivar ivar = ivars[i];
// // 查看成员变量
// const char * name = ivar_getName(ivar);
// // 归档
// NSString * key = [NSString stringWithUTF8String:name];
// id value = [self valueForKey:key];
// [encoder encodeObject:value forKey:key];
// }
// free(ivars);
//}
//
//- (instancetype)initWithCoder:(NSCoder *)decoder{
// if (self = [super init]) {
// unsigned int count = 0;
// Ivar * ivars = class_copyIvarList([Person class], &count);
//
// for (int i = 0; i < count; i++) {
// // 取出i位置对应的成员变量
// Ivar ivar = ivars[i];
// // 查看成员变量
// const char * name = ivar_getName(ivar);
// // 解档
// NSString * key = [NSString stringWithUTF8String:name];
// id value = [decoder decodeObjectForKey:key];
// // 设置到成员变量身上
// [self setValue:value forKey:key];
// }
// free(ivars);
// }
// return self;
//}
@end