有些初學者有可能在死記硬背Runtime的作用,為了應付面試,我在這就先簡單介紹一下為什么要有Runtime的NSCoding的自動歸檔、接檔(大牛可以略過)。
本地存儲數據的時候大概有四種方式
1、NSUserDefaults
2、NSKeyedArchiver
3、SQLite
4、Write
在這1、3、4就不多說了,用NSKeyedArchiver歸檔存儲數據的時候就需要遵循NSCoding協議了,要實現里面的歸檔、接檔
//歸檔方法
- (void)encodeWithCoder:(NSCoder *)aCoder
{
? ? //當學生被歸檔,學生要將成員都歸檔
? ? ? ? ?[aCoder encodeObject:self.name forKey:@"name"];
? ? ? ? ?[aCoder encodeInteger:self.age forKey:@"age"];
}
//解歸檔方法
- (id)initWithCoder:(NSCoder *)aDecoder
{
? ? ? ? ? if (self = [super init]) {
? ? ? ? ? ? ? ? ? //當學生被解歸檔,學生要將成員都解歸檔
? ? ? ? ? ? ? ? ? self.name = [aDecoder decodeObjectForKey:@"name"];
? ? ? ? ? ? ? ? ? self.age = [aDecoder decodeIntegerForKey:@"age"];
? ? ? ? ? ?}
? ? ? ? ? return self;
}
現在看起來還可以吧,這是因為數據少的情況下,如果數據有幾十條呢?寫幾十行這種代碼,你感覺怎么樣?只要錯一個字節,你這個數據就是沒有的。
這種情況就出現了今天要說的主題了:Runtime的自動歸檔、接檔。
Runtime有一個方法可以獲取當前類里面的屬性列表,既然成員變量都能拿到,每一個成員變量所對應的key以及value當然也可以拿到,這樣就不需要自己一行一行的去歸檔,接檔了。
#import "person.h"?
#import@implementation person
// 接檔讀數據
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
? ? ? ? ? ? ?if (self = [super init]) ?{
? ? ? ? ? ?/*
? ? ? ? ? ? ? OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
? ? ? ? ? ? ? Class cls 表示獲取那一個類的屬性列表
? ? ? ? ? ? ? ?unsigned int *outCount 用于存儲獲取到屬性個數
? ? ? ? ? */
? ? ? ? ? unsigned int count = 0;
? ? ? ? ? Ivar *ivar = class_copyIvarList([self class], &count);
? ? ? ? ?for (int i = 0; i < count; i++) {
? ? ? ? ? ? ? ? //根據每一個屬性取出對應的key 注意key值是c語言的key
? ? ? ? ? ? ? ? ?Ivar iva = ivar[i];
? ? ? ? ? ? ? ? ?const charchar *key = ivar_getName(iva);
? ? ? ? ? ? ? ? ?// 轉換為oc?
? ? ? ? ? ? ? ? ?NSString *strName = [NSString stringWithUTF8String:key];?
? ? ? ? ? ? ? ? ?//進行解檔取值
? ? ? ? ? ? ? ? id value = [aDecoder decodeObjectForKey:strName];
? ? ? ? ? ? ? ? //利用KVC對屬性賦值
? ? ? ? ? ? ? ? ?[self setValue:value forKey:strName];
? ? ? ? ? }
? ? ? ? ? free(ivar);
? ?}
return self;
}
// 歸檔存數據
- (void)encodeWithCoder:(NSCoder *)aCoder {
? ? ? ? ?unsigned int count;
? ? ? ? ?Ivar *ivar = class_copyIvarList([self class], &count);
? ? ? ? ?for (int i=0; i < count; i++) {
? ? ? ? ? ? ? ? ?Ivar iv = ivar[i];
? ? ? ? ? ? ? ? ?const charchar *name = ivar_getName(iv);
? ? ? ? ? ? ? ? ?NSString *strName = [NSString stringWithUTF8String:name];
? ? ? ? ? ? ? ? //利用KVC取值
? ? ? ? ? ? ? ? id value = [self valueForKey:strName];
? ? ? ? ? ? ? ? [aCoder encodeObject:value forKey:strName];
? ? ? ? ?}
? ? ? ? ? ?free(ivar);
}
需要注意的一個細節就是當涉及到Runtime的時候。一定要記得內存的釋放。Xcode的ARC只適用于OC,對于C的指針,要記得手動free。