YYModel原理分析

一.結(jié)構(gòu)分析
1.文件構(gòu)成
YYModel.h、YYClassInfo.h、NSObject+YYModel
2.核心類結(jié)構(gòu)
YYClassInfo 是對于Class進(jìn)行了封裝,進(jìn)行封裝增加描述
YYClassIvarInfo 對 Class的Ivar進(jìn)行了進(jìn)行封裝增加描述
YYClassMethodInfo 對 Class 的 Method進(jìn)行封裝增加描述
YYClassPropertyInfo 對 Class 的 Property進(jìn)行了封裝描述
YYModel :
YYModelMeta 對YYClassInfo進(jìn)行封裝描述
YYModelPropertyMeta對YYClassProperty進(jìn)行封裝描述

二、常用的方法

類別的實例的isa指針指向其類別,類別的isa指向其元類,而所有類別的元類最終都指向上帝類的元類也就是NSObject的元類。這樣形成了一個完美的繼承鏈.
instance->class->metaclass


Class object_getClass(id obj)
{
    if (obj) return obj->getIsa();
    else return Nil;
}

+ (Class)class {
    return self;
}

- (Class)class {
    return object_getClass(self);
}

Person *obj = [Person new];
NSLog(@"instance         :%p", obj);
NSLog(@"class            :%p", object_getClass(obj));
NSLog(@"meta class       :%p", object_getClass(object_getClass(obj)));
NSLog(@"root meta        :%p", object_getClass(object_getClass(object_getClass(obj))));
NSLog(@"root meta's meta :%p", object_getClass(object_getClass(object_getClass(object_getClass(obj)))));
NSLog(@"---------------------------------------------");
NSLog(@"class            :%p", [obj class]);
NSLog(@"meta class       :%p", [[obj class] class]);
NSLog(@"root meta        :%p", [[[obj class] class] class]);
NSLog(@"root meta's meta :%p", [[[[obj class] class] class] class]);

2016-02-02 18:06:11.443 TimerDemo[1718:248402] instance         :0x7fc792530f20
2016-02-02 18:06:11.444 TimerDemo[1718:248402] class            :0x10ae0e178
2016-02-02 18:06:11.444 TimerDemo[1718:248402] meta class       :0x10ae0e150
2016-02-02 18:06:11.444 TimerDemo[1718:248402] root meta        :0x10b66a198
2016-02-02 18:06:11.444 TimerDemo[1718:248402] root meta's meta :0x10b66a198
2016-02-02 18:06:11.444 TimerDemo[1718:248402] ---------------------------------------------
2016-02-02 18:06:11.444 TimerDemo[1718:248402] class            :0x10ae0e178
2016-02-02 18:06:11.444 TimerDemo[1718:248402] meta class       :0x10ae0e178
2016-02-02 18:06:11.444 TimerDemo[1718:248402] root meta        :0x10ae0e178
2016-02-02 18:06:11.444 TimerDemo[1718:248402] root meta's meta :0x10ae0e178

0.objc_
objc_allocateClassPair
objc_registerClassPair

1.class_
class_isMetaClass
class_addMethod

Ivar class_getInstanceVariable ( Class cls, const char *name ):類中指定名稱實例成員變量的信息
Ivar class_getClassVariable ( Class cls, const char *name ):類成員變量的信息
BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types ): 添加成員變量
class_copyMethodList:獲取方法列表 含有g(shù)etter 和 setter
class_copyPropertyList:獲取屬性列表
class_copyIvarList ( Class cls, unsigned int *outCount );獲取整個成員變量列

2.Method
_sel=method_getName:
sel_getName:
method_getImplementation:
method_getTypeEncoding
method_copyReturnType
method_getNumberOfArguments
method_copyArgumentType

3.objc_property_t
property_getName
property_copyAttributeList

4.Ivar
ivar_getName:
ivar_getOffset:
ivar_getTypeEncoding:

Class newClass = 
    objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0); 
class_addMethod(newClass, @selector(report), (IMP)ReportFunction, "v@:"); 
objc_registerClassPair(newClass); 

三.函數(shù)分析
1.yy_modelWithJSON:
NSDic、NSData、NSString 都轉(zhuǎn)成NSDic.
NSString->NSData->NSDic

NSData *jsonData= [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding]
 NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL]

2.YYModelMeta metaWithClass
創(chuàng)建一個總的CFMutableDictionaryRef緩存,保存每個model,(Key:Class Value:YYModelMeta)
采用dispatch_semaphore
信號量機(jī)制保證線程讀取安全
create\wait\signal

a.
Class cls = [self class];
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls]
meta = [[_YYModelMeta alloc] initWithClass:cls];
YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
b.讀取代理的 blacklist、whitelist
c.獲取類型需要映射數(shù)組 modelContainerPropertyGenericClass
{ @"rightImage" : [FHWHomeRightImage class] }
{ @"rightImage" : @"FHWHomeRightImage" } //FHWHomeRightImage這個需要轉(zhuǎn)化

d.Create all property metas. 對真正要映射屬性進(jìn)行遍歷組裝成一個數(shù)組
d1.判斷是否再黑白名單里面才需要處理
d2.生成_YYModelPropertyMeta。入?yún)?classinfo 、propertyInfo、genericMapper[propertyInfo.name]。 一定要有g(shù)etter setter。
包括superclass,也要一并生成進(jìn)來。
d3.無視最基類的屬性NSObject/NSProxy
while (curClassInfo && curClassInfo.superCls != nil) { // recursive parse super class, but ignore root class (NSObject/NSProxy)

e.// create mapper
modelCustomPropertyMapper

f.yy_modelSetWithDictionary 最后填充映射函數(shù)

f1.modelCustomWillTransformFromDictionary:傳入映射前,再次進(jìn)行修改。
f2.CFArrayApplyFunction:遍歷Array數(shù)組元素,每一次傳入一個函數(shù)中進(jìn)行處理
CFDictionaryApplyFunction:遍歷
f3.
f4._hasCustomTransformFromDictionary

propertyMeta->_mappedToKeyArray
propertyMeta->_mappedToKeyPath
_isCNumber:C語言格式的數(shù)字 特殊處理
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);

3.YYClassInfo classInfoWithClass

創(chuàng)建兩個緩存 classCache、metaCache
a.當(dāng)你向一個對象發(fā)送消息,就在那個對象的方法列表中查找那個消息。
b.當(dāng)你想一個類發(fā)送消息,就再那個類的 meta-class 中查找那個消息。
NSStringEncoding defaultStringEncoding = [NSString defaultStringEncoding];
c.含有一個YYClassInfo *superClassInfo的指針。
d.
NSType
非NSType開頭
(modelCustomClassForDictionary:)
4.initWithMethod
NSDic存儲 HomeKey:YYClassMethodInfo
Method *methods = class_copyMethodList(cls, &methodCount);
普通變量含有 get set的方法、.cxx_destruct
@"HomeKey" 、@"setHomeKey:"
method_getTypeEncoding : "@16@0:8" 、"v24@0:8@16"
method_copyReturnType :"@" 、"v"
method_copyArgumentType : 2 {"@" 、":"} 、3{"@"、":"、"@"}
cxx_destruct:向父類轉(zhuǎn)發(fā)dealloc的調(diào)用,實現(xiàn)了自動調(diào)用[super dealloc]

5.initWithProperty
NSDic存儲 HomeKey:YYClassPropertyInfo
objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
attrs里面值:
nsstring {"T","NSString"}、copy {"'C'",""}、nonatomic{"N",""}、HomeKey{"V"、"_HomeKey"}.

如果沒有顯示指定set 、get ,通過變量名自動生成 getter和setter "HomeKey" "setHomeKey:"。

Class cls :NSString
NSArray<NSString *> *protocols: 協(xié)議<>
case '&': YYEncodingTypePropertyRetain;
case 'W' :YYEncodingTypePropertyWeak

YYEncodingGetType: 先判斷是否是修飾符 in、out 之類 再判斷是否指定類型 NSInterger,如果是"@”,開頭,區(qū)分object和block.block只有2個長度固定為"@?'"

6.Ivar
Ivar *ivars = class_copyIvarList(cls, &ivarCount);
ivar_getName:"_HomeKey"
ivar_getOffset:8
ivar_getTypeEncoding:"@NSString"
_type:YYEncodingTypeObject

7.muikey和key path

image.png

8.反向轉(zhuǎn)化model 轉(zhuǎn) object
8.1ModelToJSONObjectRecursive
遞歸遍歷

優(yōu)先判斷是否基礎(chǔ)類型,如果是直接返還。如果是判斷傳進(jìn)來是數(shù)組或者字典。先創(chuàng)建一個空的數(shù)組或者字典,再把數(shù)組或者字典實體進(jìn)行轉(zhuǎn)化,再存進(jìn)這個空的數(shù)組或者字典,然后返回。

8.2驗證最后的結(jié)果
只能是NSArray、NSDictionary

9.特殊備注
9.1.[instancesRespondToSelector與respondsToSelector的區(qū)別
instancesRespondToSelector只能寫在類名后面(類的靜態(tài)方法+),respondsToSelector可以寫在類名和實例名后面。
9.2.特殊類型 nsdata、nsurl、NSAttributedString、NSNumber、
nstype:接收的類型 NSString得做轉(zhuǎn)化,NSMutableString .stringValue.mutableCopy

((void (*)(id,SEL,id))(void *) objc_msgSend)((id)model,meta->_setter,value);

       YYEncodingTypeNSValue:
       YYEncodingTypeNSNumber:
       YYEncodingTypeNSDecimalNumber:

b.NSDecimalNumber、NSValue直接映射,其他類型先轉(zhuǎn)成NSDecimalNumber再映射。
c.NSDate 接手為NSString 幫你手動轉(zhuǎn)化
d.NSArray
f.NSDictionary
g.NSSet
h.YYEncodingTypeObject\

CFArrayApplyFunction

主要類別

NSObject(YYModel) : 提供一些字典模型互轉(zhuǎn)的方法,將對key/value進(jìn)行匹配,賦值給Model對應(yīng)的property
NSArray(YYModel): 為NSArray提供字典轉(zhuǎn)模型的方法
NSDictionary(YYModel):為NSDictionary提供字典轉(zhuǎn)模型方法

在 ARC 條件下,默認(rèn)聲明的對象是 strong 類型的,賦值時有可能會產(chǎn)生 retain/release 調(diào)用,如果一個變量在其生命周期內(nèi)不會被釋放,則使用 unsafe_unretained 會節(jié)省很大的開銷。


123.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容