一 .概述
一直聽說(shuō)runTime是各種神奇,可以動(dòng)態(tài)添給Category動(dòng)態(tài)綁定屬性,可以自動(dòng)解析Json,還有動(dòng)態(tài)交換方法,還有利用RunTime實(shí)現(xiàn)自動(dòng)化歸檔,今天就跟大家分享下利用RunTime如何實(shí)現(xiàn)自動(dòng)化歸檔.
二.RunTime
- RunTime簡(jiǎn)稱運(yùn)行時(shí)。就是系統(tǒng)在運(yùn)行的時(shí)候的一些機(jī)制;利用它可以做好多有趣的事情,我就不在這里一一說(shuō)了,利用RunTime 實(shí)現(xiàn)自動(dòng)化歸檔 主要運(yùn)用到下面幾個(gè)方法:
- 獲取當(dāng)前屬性列表
OBJC_EXPORT Ivar *class_copyIvarList(Class cls, unsigned int *outCount)
1.Ivar 定義對(duì)象的實(shí)例變量,包括類型和名字(運(yùn)行時(shí))
2.第一個(gè)參數(shù)是傳入的是需要獲取屬性列表的類名
3.第二個(gè)參數(shù)傳入一個(gè)int 類型的地址 需要&地址符號(hào)
返回變量名,char集合,需要進(jìn)行UTF8轉(zhuǎn)碼
OBJC_EXPORT const char *ivar_getName(Ivar v)用來(lái)查找當(dāng)前類是否有某個(gè)方法
OBJC_EXPORT BOOL class_respondsToSelector(Class cls, SEL sel)
1.第一個(gè)參數(shù) 是需要查找方法的類
2.需要查找的方法
三.自動(dòng)化歸檔
-
第一步獲取當(dāng)前類的屬性列表
// 獲取屬性列表
- (NSArray *)getPropertyNameList
{
unsigned int count;
// 獲取屬性列表
objc_property_t *property_list = class_copyIvarList([self class], &count);NSMutableArray *property = [NSMutableArray array]; for (int i = 0; i < count; i++) { const char *name = property_getName(property_list[i]); NSString *string = [NSString stringWithUTF8String:name]; NSLog(@"當(dāng)前的屬性名字%@",string); [property addObject:string]; } return [property copy]; }
-
根據(jù)屬性名字,匹配get方法進(jìn)行歸檔
// 數(shù)據(jù)歸檔
// 因?yàn)間et方法默認(rèn)省略get關(guān)鍵字所以直接用屬性名字就可以訪問(wèn) get 方法
- (void)encodeWithCoder:(NSCoder *)aCoder
{
// 獲取當(dāng)前屬性列表;
NSArray *property = [self getPropertyNameList];for (NSString *propertyName in property) { // 因?yàn)間et方法默認(rèn) 是省略get關(guān)鍵字的 SEL getSEL = NSSelectorFromString(propertyName); if (class_respondsToSelector([self classForCoder], getSEL)) { id value = [self performSelector:getSEL]; // 如果value 有值 則進(jìn)行保存 if (value) { [aCoder encodeObject:value forKey:propertyName]; NSLog(@"have value name %@", propertyName); } } } }
-
根據(jù)屬性名字,匹配set方法進(jìn)行解檔處理
// 協(xié)議方法 解檔數(shù)據(jù)
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
NSArray *property = [self getPropertyNameList];for (NSString *propertyName in property) { // 大寫第一個(gè)字母 NSString *first = [[propertyName substringToIndex:1] uppercaseString]; // 重新拼接方法 setPropertyName 命名規(guī)范 注意: set方法需參數(shù)需要拼接":" SEL setSEL = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:",first,[propertyName substringFromIndex:1]]); if (class_respondsToSelector([self class], setSEL)) { id value = [aDecoder decodeObjectForKey:propertyName]; // 如果value有值 再進(jìn)行賦值 if (value) { [self performSelector:setSEL withObject:value]; NSLog(@"解當(dāng)數(shù)據(jù),屬性%@的值%@", propertyName,value); } } } return self; }
總結(jié)
在實(shí)現(xiàn)方法的過(guò)程中發(fā)現(xiàn)的一個(gè)需要注意的細(xì)節(jié),就是當(dāng)按照屬性名字去匹配setter方法時(shí)由于set方法需要傳遞參數(shù),需要在名字后面拼接 ":" ;因?yàn)樵贠bjective-C中冒號(hào)也是函數(shù)名字的一部分,所以一定要把冒號(hào)給加上.以上三個(gè)方法就可以實(shí)現(xiàn)自動(dòng)歸檔了,剩下的就是一些業(yè)務(wù)封裝了,每個(gè)人都有自己偏愛(ài)的方法,我自己也封裝了一個(gè), 有需要的可以留言.(只需要繼承這個(gè)父類,然后只需要在子類的.h文件里添加屬性就可以實(shí)現(xiàn)自動(dòng)歸檔了)