YYModel原理分析

一.结构分析
1.文件构成
YYModel.h、YYClassInfo.h、NSObject+YYModel
2.核心类结构
YYClassInfo 是对于Class进行了封装,进行封装增加描述
YYClassIvarInfo 对 Class的Ivar进行了进行封装增加描述
YYClassMethodInfo 对 Class 的 Method进行封装增加描述
YYClassPropertyInfo 对 Class 的 Property进行了封装描述
YYModel :
YYModelMeta 对YYClassInfo进行封装描述
YYModelPropertyMeta对YYClassProperty进行封装描述

二、常用的方法

类别的实例的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:获取方法列表 含有getter 和 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); 

三.函数分析
1.yy_modelWithJSON:
NSDic、NSData、NSString 都转成NSDic.
NSString->NSData->NSDic

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

2.YYModelMeta metaWithClass
创建一个总的CFMutableDictionaryRef缓存,保存每个model,(Key:Class Value:YYModelMeta)
采用dispatch_semaphore
信号量机制保证线程读取安全
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.获取类型需要映射数组 modelContainerPropertyGenericClass
{ @"rightImage" : [FHWHomeRightImage class] }
{ @"rightImage" : @"FHWHomeRightImage" } //FHWHomeRightImage这个需要转化

d.Create all property metas. 对真正要映射属性进行遍历组装成一个数组
d1.判断是否再黑白名单里面才需要处理
d2.生成_YYModelPropertyMeta。入参 classinfo 、propertyInfo、genericMapper[propertyInfo.name]。 一定要有getter setter。
包括superclass,也要一并生成进来。
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 最后填充映射函数

f1.modelCustomWillTransformFromDictionary:传入映射前,再次进行修改。
f2.CFArrayApplyFunction:遍历Array数组元素,每一次传入一个函数中进行处理
CFDictionaryApplyFunction:遍历
f3.
f4._hasCustomTransformFromDictionary

propertyMeta->_mappedToKeyArray
propertyMeta->_mappedToKeyPath
_isCNumber:C语言格式的数字 特殊处理
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);

3.YYClassInfo classInfoWithClass

创建两个缓存 classCache、metaCache
a.当你向一个对象发送消息,就在那个对象的方法列表中查找那个消息。
b.当你想一个类发送消息,就再那个类的 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:向父类转发dealloc的调用,实现了自动调用[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: 协议<>
case '&': YYEncodingTypePropertyRetain;
case 'W' :YYEncodingTypePropertyWeak

YYEncodingGetType: 先判断是否是修饰符 in、out 之类 再判断是否指定类型 NSInterger,如果是"@”,开头,区分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.反向转化model 转 object
8.1ModelToJSONObjectRecursive
递归遍历

优先判断是否基础类型,如果是直接返还。如果是判断传进来是数组或者字典。先创建一个空的数组或者字典,再把数组或者字典实体进行转化,再存进这个空的数组或者字典,然后返回。

8.2验证最后的结果
只能是NSArray、NSDictionary

9.特殊备注
9.1.[instancesRespondToSelector与respondsToSelector的区别
instancesRespondToSelector只能写在类名后面(类的静态方法+),respondsToSelector可以写在类名和实例名后面。
9.2.特殊类型 nsdata、nsurl、NSAttributedString、NSNumber、
nstype:接收的类型 NSString得做转化,NSMutableString .stringValue.mutableCopy

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

       YYEncodingTypeNSValue:
       YYEncodingTypeNSNumber:
       YYEncodingTypeNSDecimalNumber:

b.NSDecimalNumber、NSValue直接映射,其他类型先转成NSDecimalNumber再映射。
c.NSDate 接手为NSString 帮你手动转化
d.NSArray
f.NSDictionary
g.NSSet
h.YYEncodingTypeObject\

CFArrayApplyFunction

主要类别

NSObject(YYModel) : 提供一些字典模型互转的方法,将对key/value进行匹配,赋值给Model对应的property
NSArray(YYModel): 为NSArray提供字典转模型的方法
NSDictionary(YYModel):为NSDictionary提供字典转模型方法

在 ARC 条件下,默认声明的对象是 strong 类型的,赋值时有可能会产生 retain/release 调用,如果一个变量在其生命周期内不会被释放,则使用 unsafe_unretained 会节省很大的开销。


123.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,302评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,232评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,337评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,977评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,920评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,194评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,638评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,319评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,455评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,379评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,426评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,106评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,696评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,786评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,996评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,467评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,043评论 2 341

推荐阅读更多精彩内容