利用運行時實現歸檔、解檔,并將其封裝成宏
- 繼承
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