傳統的歸檔通常我們都需要先遵循NSCoding協議,然後根據每個屬性,每個屬性不同的型別去呼叫不同的方法來實現我們的歸檔。詳情請見我的另一篇簡書歸檔與反歸檔,在這裡我就不詳細介紹了。 下面我們就開始用runtime來實現我們的一個萬能歸檔。 1.首先我們還是要讓物件遵循NSCoding協議,並實現相關的兩個方法,示例如下所示。
@interface NSAchive : NSObject<NSCoding>
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *url;
@property (assign, nonatomic) NSInteger age;
@property (strong, nonatomic) NSString *gender;
@end
複製程式碼
需要實現的方法為
- (void)encodeWithCoder:(NSCoder *)aCoder
{
}
複製程式碼
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
}
複製程式碼
眾所周知runtime是OC的幕後工作者,都聽說過他的強大,那我它的強大之處在哪裡呢,它存在的價值就是能夠解決我們OC無法解決的問題,例如獲取類的所有屬性名。在OC中我們都知道,一旦屬性被宣告為私有的,我們就不能訪問到了。但是runtime可以幫我們實現這一點,不管你的屬性宣告為私有還是公開的,我們都可以通過runtime來獲取,下面我們就來看看它是如何獲取的。 廢話不多說,上程式碼
unsigned int count = 0; //宣告一個無符號整型的變數,用它來統計我們屬性的個數。
Ivar *ivars = class_copyIvarList([self class], &count);//class_copyIvarList這個函式的意思是拷貝出整個類的屬性列表,它需要兩個引數,一個是類名,還有一個無符號的整型變數的地址,在C語言中,要想在函式中改變一個變數的值,那麼就要通過記憶體地址去對他進行操作。
for (int i = 0; i < count; i++) {
const char *ivar = ivar_getName(ivars[i]);//我們通過對記憶體地址的偏移,來獲取每個屬性的屬性名。這樣我們就獲取到了這個類中每個屬性名了。
NSString *propretyName = [NSString stringWithUTF8String:ivar];
}
複製程式碼
不要忘記在使用runtime的時候需要引入相關的標頭檔案**#import <objc/runtime.h>** 2.通過上面的方法,我們已經成功的獲取到了每個屬性的名稱了。那麼我們又有一個新的問題了,該如何給屬性賦值。相信大家都聽過KVC吧,(我有一篇介紹KVC和KVO的文章,有興趣的可以去看看iOS KVC與KVO)接下來我們就用KVC來解決我們的這個問題
- 歸檔的時候,通過KVC賦值
- (void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
const char *ivar = ivar_getName(ivars[i]);
NSString *propretyName = [NSString stringWithUTF8String:ivar];
[aCoder encodeObject:[self valueForKey:propretyName] forKey:propretyName];
}
}
複製程式碼
- 反歸檔,通過KVC取值
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i++) {
const char *ivar = ivar_getName(ivars[i]);
NSString *propretyName = [NSString stringWithUTF8String:ivar];
id value = [aDecoder decodeObjectForKey:propretyName];
[self setValue:value forKey:propretyName];
}
}
return self;
}
複製程式碼
3.然後我們歸檔和反歸檔的時候就不用再像原來一樣去寫那麼多的程式碼了
- 歸檔
NSAchive *achive = [[NSAchive alloc]init];
achive.name = @"王維";
achive.age = 33;
achive.gender = @"男";
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"my.iiisdsd"];
NSLog(@"%@",NSHomeDirectory());
[NSKeyedArchiver archiveRootObject:achive toFile:filePath];
複製程式碼
- 反歸檔
NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent:@"my.iiisdsd"];
NSAchive *achive = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
NSLog(@"我叫%@,今年%ld歲,性別%@。",achive.name,achive.age,achive.gender);
複製程式碼
以後我們歸檔和反歸檔就可以這樣做了,是不是很方便呢,如果我的文章正好解決了你的問題,請喜歡並且關注我,你們的支援是我最大的動力。