一.結(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
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é)省很大的開銷。