iOS-穿针引线 YYModel全英文注解解析翻译+超详细分析!敢问还有哪位比我还详实!!还有谁!!!

本身之英文能力不够,所以自己把笔者提供的英文注释解析通过字典百度自己之领悟等方式翻译后写下去,再比自己之翻与各方查询的素材来分析。若认为对,可否给颗star?你的支持用凡自家的动力。

接触我入Git下充斥

//mapped to 映射//列子 instancetype 通常也靠实例

除非分析,注释请下载后看到(麻烦下充斥前随手star一下,你的支持以凡自己的动力!),建议太对比源码观看。

是因为内容了多,先只说下通过JSON创建并返一个实例的分析

+(instancetype)ad_modelWithJSON:(id)json:

当那个中间其实通过类似方式[self
_ad_dictionaryWithJSON:json]创建了一个字典,而后通过类似方式[self
ad_modelWithDictionary:dic]创办并返所待的实例

+(NSDictionary *)_ad_dictionaryWithJSON:(id)json 

看似措施,自定义之落实方式并从未对应的法门声明,接收及Json文件后先判断Json文件是否为空,判断有些许栽方式
if (!json || json == (id)kCFNull)  

kCFNull: NSNull的单例,也便是拖欠的意那为何不用Null、Nil或nil呢?

以下为nil,Nil,Null,NSNull的区别

Nil:对类进行赋空值

ni:对目标进行赋空值

Null:对C指针进行赋空操作,如字符串数组的首地址 char *name = NULL

NSNull:对组合值,如NSArray,Json而言,其内部有价,但价值吗空

因此判断标准json不在或者json存在,但是那里面价也空,就一直回nil。若json存在且该中间发生价,则开创一个空字典(dic)与空NSData(jsonData)值而后又判断,若json是NSDictionary类,就径直赋值给字典。

要是NSString类,就将该挟持转化为NSString,而后用UTF-8编码处理赋值给jsonData。

比方NSData,就一直赋值给jsonData而后判,而jsonData存在就意味着json值转化为二进制NSData。

故此合法提供的JSON解析就只是取得到所待的价赋值为dic。若发现解析后得到到得值不是NSDictionary,就代表值未克也dict,因为无是同品种值,就于dict为nil最后回到dict。

以是方式里一定给若JSON文件也NSDictionary类型或只是分析成dict的NSData、NSString类型就赋值给dict返回,若无克则赶回的dict为nil

+(instancetype)ad_modelWithDictionary:(NSDictionary *)dictionary 

恍如措施,方法中会先判断若字典不有,或字典存在但值为空的情状下直接返回nil而后于认清若污染过来的字典其实不是NSDictionary类型,则为回nil。所以,到了产一致步时即便表示字典存在都值未为空,而且污染过来的字典就是NSDictionary类型,则开创一个类Cls为目前调用方法的类似,而后通过从定义方法[_ADModelMeta
metaWithClass:Cls]用自家类传过去。

_ADModelMeta为延展类实现方式里声称的近乎,metaWithClass:Cls方法吗

+(instancetype)metaWithClass:(Class)cls

仿佛方式,方法返回这个class元素,model缓存在方法中,会先判断若cls不设有则回nil而一旦在,则开创三独静态属性:CFMutableDictionaryRef
cache(static,静态修饰符,被static修饰的性能在次结束前未会见于销毁。CFNSMutableDictionaryRef,可更换字符串底层,效率比其高).

dispatch_semaphore_t 
lock(同步信号量,一赖实施中让其值为1尽管wait时便会见由此继续执行),dispatch_once_t
oncetoken(一不好执行,配合dispatch_once以,整个程序只见面执行同样不善)一不善实施着创造CFMutableDictionaryRef与dispatch_semaphore_create(1)

中间CFMutableDictionary的开创中四只参数意义为: cache =
CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);

 @功能 CFDictionaryCreateMutable创建一个初的词典。

 @参数 CFAllocator
分配器应该用于分配CFAllocator字典的内存和其值的贮存。这
参数可能吗空,在这种状况下,当前的默认值CFAllocator使用。如果这个引用不是一个得力之cfallocator,其行为是勿定义的。这里是外存及其值的蕴藏吗默认。

 @参数 capacity
暗示值得个数,通过0实现可能忽略这个提示,或者好采取它们来优化各种。这里是忽视。

 @参数 keyCallBacks
指向CFDictionaryKeyCallBacks结构吧即仍字典使用回调函数初始化在字典中之各级一个键,初始化规则太多又看之稍晕就未多说了,毕竟不敢乱说。意思应该是本着键值对遭之键进行初始化,并出照应的优化措施。 

 @参数 valueCallBacks
指向CFDictionaryValueCallBacks结构也当时本词典使用回调函数初始化字典中之每一个价值。对键值对面临的价进行初始化,并出对应地优化措施。

同样次等实行后通过wait判断是否继续执行,由于Create值为1所为可直通一次于,此时当CF字典cache中得价值不可变的函数指针cls对应的价值_ADModelMeta
*meta(const 值不可让移,void *
函数指针,通过__bridge桥过渡转换)而后通过signal操作让lock锁的信号加1,再错过执行判断语句。

认清内容吗若meta不在,或meta存在而彼属性classInfo(ADClassInfo
*列)的needUpdate为YES代表meta需要更新或存储,则经过_ADModelMeta对象方法(instancetype)initWithClass:(Class)cls
获取一个实例。

-(instancetype)initWithClass:(Class)cls 

艺术外,会先通过[ADClassInfo
classInfoWithClass:(Class)cls]获得到cls的信息一旦以[ADClassInfo
classInfoWithClass:(Class)cls]主意中,又见面先行失判断Cls是否有,若无存回nil若在,则开创两单CFMutableDictionaryRef(metaCache与classCache)与一个相同软实行,一个协同信号量。

自此通过同样糟实施初始化两单CFMutableDictionaryRef与协同信号量的初始化创建了后会见预先判断同步信号量,由于初始化有值则减一继继续推行这创造一个ADClassInfo
*info用于保存通过CFDictionaryGetValue获取到之Class信息。

其中class_isMetaClass判断指定类是否是一个元类

元类是接近对象的接近,如[NSArray
array]未遭的NSArray也是一个靶,NSArray通过元类生成,而元类又是一个对象,元类的切近是根源类NSObject,NSObject父类为Nil

苟是元类则存储在metaCache中,所以啊是于内部取值,如果非是就是囤在classCache中为便是从classCache中取值,通过一个不可变的函数指针cls取值而后同步信号量加1
若取得到消息info则直接归,若取不至就是因[[ADClassInfo alloc]
initWithClass:cls];去获取Info。

[[ADClassInfo alloc] initWithClass:cls]
私有主意,未在.h文件被宣示在斯办法被会事先判断传过来的cls是否留存,若不存在回nil若在,就先行经过父类初始化一涂鸦并保存传过来的_cls
= Cls,与Cls的父类(_superCls =
class_getSuperclass(cls)获取父类)以及Cls是否也元类的Bool值( _isMeta = 
class_isMetaClass(cls)),若不是元类则得到该元类并保存(_metaCls =
objc_getMetaClass(class_getName(cls))),以及近似的讳(_name =
NSStringFromClass(cls))而继调整用相同破_update方法。

当update方法里会事先对ivarInfos(ivars)methodInfos(methods)
propertyInfos(properties)三只属性初始化,ivars属性,methods方法,properties属性操作并临时保存self.cls(之前正赋值)。

宣示一个 保存 方法描述的数组指针 长度值 methodCount。 Method *methods =
class_copyMethodList(cls,
&methodCount);返回关于目标方法描述的一个数组指针,数组长度保存于methodCount地址里。

设若指针存在,就创造一个NSMutableArray字典存储方,并保存之字典_methodInfos
= methodInfos; 而后又通过由定义方法[[ADClassMethodInfo alloc]
initWithMethod:methods[i]];通过污染过来的方式返回一个实例-(instancetype)initWithMethod:(Method)method通过污染过来的法子返回一个实例。

以是办法里会优先判断方式是否存在,若未存在回nil,若存在则保留方法method,与法操作SEL(method_getName(method)),方法实现IMP(method_getImplementation(method)),方法操作的名(
const char *name
=sel_getName(_sel),返回值是一个价值不可变的字符指针name,字符指针通常对一个字符数组的首地址,字符数组看似于字符串)

若取得到名字则用艺术名用UTF-8编码后保存。方法参数与归值类型(method_getTypeEncoding(method))若取得到通过UTF-8编码后保存。方法的回到值类型(method_copyReturnType(method))若取得到则经过UTF-8编码后保存。

办法的参数个数(method_getNumberOfArguments(method))若个数大于0,则开创一个但变数组,而后去遍历获取参数类型(method_copyArgumentType(method,
i)获取方式的指定位置参数的花色字符串),若得到的参数类型有就是由此UTF-8编码后拿走,不设有即也nil,而后保存及但是变数组里,若有价则存储,没有值用@“”代替,存储后而得到之参数类型是就是free释放其内存,全部抱后保存之数组。

说到底将保存好信息之self返回此时返回_update方法里,已经经过对象获得得到一个计的叙述信息,判断方式名(name,方法操作的名)是否出价,如发价则盖之也key,对象呢价值存储在可变换字典methodInfos里,而methodInfos之前都为保留。没有当就是无抱了。

一切囤完毕后获释methods内存(之前获得的关于目标方法描述的一个数组指针)。获取到数组后,去抱cls的属性。同理,先通过class_copyPropertyList获取到性个数存储在一个unsigned
int(无符号整型)值备受,再获属性描述properties,如果来总体性则属性描述有价。

这时创并保存一个但转移字典,而后遍历属性,并以尽历时的性质通过[[ADClassPropertyInfo
alloc]
initWithProperty:properties[i]];封装成一个ADClassPropertyInfo对象,以属性名为Key属性,对象啊价值存储在字典里储存完晚放走属性描述内存。

-(instancetype)initWithProperty:(objc_property_t)property

主意吃,依旧是先行判断后保存,保存了招过来的性,属性的名称,属性的特点列表指针objc_property_attribute_t
*(通常代表该是一个数组,一个结构体包含一个name属性的叙述,一个value属性值),而后遍历此指针指向的数组开始一个一个取值保存于新建的objc_property_attribute_t中。

若取出来的name皆是以T开头后面和随属性类型如字典,属性是强弱指针(如&为强指针,空为Value)原子性非原子性(空为atomic,N为nonatomic),变量名称,使用UTF-8编码后保存。

以使用于定义C语言函数结构体objc_property_attribute_t中的name与Value:

结构体中的name与Value:

属性类型  name值:T  value:变化

编码类型  name值:C(copy) &(strong) W(weak) 空(assign) 等 value:无

非/原子性 name值:空(atomic) N(Nonatomic)  value:无

变量名称  name值:V  value:变化

性能描述为 T@”NSString”,&,V_str 的 str

特性之叙说:T 值:@”NSString”

性能的讲述:& 值:

性之描述:V 值:_str2

ADEncodingGetType(返回值为ADEncodingType,接收参数为不可变的字符数组typeEncoding)转换value值。

每当ADEncodingGetType中,先用而更换字符数组type保存传过来的Value值,若值未在则回从定义枚举ADEncodingTypeUnknown,若发生价则取type长度,若长度也0依照旧返回Unknown,若长度不为0尽管声明一个朵举值qualifier,在安装一个价值吗true的Bool值用于死循环,在死循环内部由字符数组type的首地址开始一个一个取出其中的字符,若满足要求则被qualifier进行各运算(1
| 0 = 1, 1 | 1 =
0)而后指针+1指为下一个值,当值未满足任何条件跳出while循环。

更取得剩余字符数组长度,若长度为0虽要运算Unknow,若未是虽然判断这的中也哪种档次及qualifier进行或者运算后回来,若否@类型即为block或Object类型,长度也2为?结尾则是Block否则就是Object,如果类型不可知则赶回qualifier与Unknow或运算值。

返回值之前的switch选择吃,此时我们获取了value的品类以及修饰符类型(如不可变的int16档次),再失去判断若Value有价,其类别又是Object类型,则应用NSScanner(条件判断)获取字符串通过scanString:intoString:判断值是否包含NULL

@\”中 \”转义符,转义成“ 所以值也@“,从@“开始遍历若找到NULL则归YES

无分包了此次巡回。若含则开创一个空字符串clsName,而后通过NSCharacterSet(一组Unicode字符,常用与NSScanner,NSString处理)转换字符串@“\“<”再连转换后的NSCharterSet扫描scanner中是否带有转换后底靶子,若含则以盛传的字符串指向的遇到charterSet字符之前内容的指针保存及&clsName地址被。

这儿之&clsName代表字符串头地址之地方,存储后只要地址被发生价,则拿价值通过UTF-8编码处理后,通过objc_getClass获取到那个isa保存(objc_getClass来得到对象的isa,isa是一个指针指向对象自我)而继再声明一个拖欠的但是变数组,用于取字符串中于“<”到“
>”中之始末,保存于新建的字符串protocol中,若有情都之前的空数组没有价值(不知底怎么大多就同步)则上加字符串给可变数组,至此,属性名为T的操作就结了。

若name属性名吧V代表是价值名称(如字符串Str,V的值Str),直接下UTF-8编码后保存R代表属性也特念属性,则叫type或运算ADEncodingTypePropertyCopyC为Copy,&为Reatin(引用计数加同,形同强指针)

N为nonatomic,D为Dynamic(@dynamic
,告诉编译器不自动生成属性的getter、setter方法)

W为weak,G为getter方法,S为setter方法

赢得到性后刑满释放属性的性状列表,保存已落之type值,若属性名称是如性的getter、setter方法没有得就由此性名称获取,至此属性列表获取了。

连片下去就抱成员变量了(成员变量和性能之操作区别在:成员变量{}中扬言的,
属性@property声明的),这个比较简单。

事先获成员变量列表、个数,若列表有价则声称一个只是变换字典并保留,而后通过打定义方法[[ADClassIvarInfo
alloc] initWithIvar:ivars[i]];获取成员变量。

-(instancetype)initWithIvar:(Ivar)ivar

法里,依旧先判断传过来的是否为空,而后保存传过来的ivar,获取成员变量名(ivar_getName(ivar)),获取得到通过UTF-8编码后保存,在获得成员变量首地方之偏移量(ivar_getOffset(ivar)),runtime会计算ivar的地址偏移来查找ivar的最后地址,获取成员变量类型编码(ivar_getTypeEncoding(ivar)),若得得到通过UTF-8编码后保存,而后再通过从定义C函数ADEncodingGetType获取type值(之前曾描述)。

迄今为止,方法method,属性property,成员变量ivar全部赢得。

获取后判断若未存在就赋空值,将_needUpdate赋值为NO回到-(instancetype)initWithClass:(Class)cls方法中,更新了晚经过自定义方法[self.class
classInfoWithClass:_superCls]博父类信息并保留,而后返回self此时归classInfoWithClass,此时早已获Cls的info信息。

如果得到info信息就实施同一糟糕共信号灯wait操作,而后通过info.isMeta判断Cls是否也元类来存储Cls的info,元类存储于metaCache中,非元类存储在classCache中,存储后叫线程同步信号灯加1归info。

怎加1?因为下次上艺术后一旦经wait,然后才会由此静态可更换CF字典取值。

这回去initWithClassC语言,获取到Cls的信,如果消息不设有回nil,存在就先通过父类初始化一不好,而后判断连取白名单,黑名单里之之习性。再定义一个不过转换字典genericMapper用于取自定义Class中含有的集合属性。

先让Cls执行方modelContainerPropertyGenericClass(若方法有执行,
描述:    如果是property是一个对象容器,列如NSArray/NSSet/NSDictionary 
实现这个艺术并返一个特性->类mapper,告知哪一个对象将吃补充加到这array
/set /)获取返回回来的字典(如:@”shadows” : [ADShadow
class],由用户书写)

若是字典有价则还声明一个可换字典tmp,而后通过Block遍历字典genericMapper,若字典Key不是字符串类型返回,若是字典则获得Key对应值的切近,获取不顶则回,获取到后判断是否是元类,如果是元类则tmp字典以genericMapper的key为自身key,以genericMapper的value为自我value,如果未是元类而是字符串类,则因为这个字符串创建一个类(NSClassFromString(obj))。

一经创建成功则坐因为genericMapper的key为自家key,以创办的好像为自身value,遍历完后保存genericMapper为tmp。而继创造有的porperty元素,先得到classInfo,如果classInfo存在并且父类不也空(预先解析父类,但忽视根类(NSObject/NSProxy))。

以后全历curClassInfo.propertyInfos.allValues(curClassInfo的字典属性propertyInfos的所有值)保存在ADClassPropertyInfo
* propertyInfo中,若propertyInfo.name不存
或暗名单是都非法名单包含propertyInfo.name 
或白名单存在且白名单不含propertyInfo.name  则结束目前轮回。

继经自定义方法[_ADModelPropertyMeta metaWithClassInfo:classInfo
propertyInfo:propertyInfo
generic:genericMapper[propertyInfo.name]]得model对象吃之property信息。

+ (instancetype)metaWithClassInfo:(ADClassInfo *)classInfo
propertyInfo:(ADClassPropertyInfo *)propertyInfo
generic:(Class)generic 

方法下次于讲述,感觉本文就写得实在有些多,总之就是是透过这个获得到model对象吃之property信息,包括getter、setter方法,可否使用KVC,可否归档解档,以及Key、keyPath、keyArray映射等。

返回initWithClass方法,若赢得到model对象中之property信息meta不存在,或meta->_name(成员变量不支持点语法)不有,或meta->_getter、meta->_setter不存在或者已经保存在字典allPropertyMetas中即使终止时轮回,若都非饱则保留在字典allPropertyMetas中。遍历结束晚保存curClassInfo为夫父类,而后再while循环直至根类while结束后若allPropertyMetas有价则保留,而后创建一个但转移字典,两独可变数组。通过modelCustomPropertyMapper方法实现定制元素

+ (nullable NSDictionary*)modelCustomPropertyMapper;

定制性元素,描述 如果JSON/Dictionary的key并无克匹配model的property
name,实现这办法并回额外的素。

先行失看清是否响应此艺术,如果能,就创造一个字典,声明是NSDictionary,但是实现时凡于定义属性映射字典,相当给响应了这个办法返回值赋值给字典customMapper,而后Block遍历次字典,通过之前存储的allPropertyMetas字典取出对诺Key的价赋值给propertyMeta,若取不发则直接return,若得出则allPropertyMetas删除Key与Key对应的价值

日后判断customMapper中的Value是否属NSString类型,若属于但长度为0则return,否则保存在propertyMeta中,随后坐”.”分割字符串为一个数组keyPath
,而后遍历数组,若合历时的字符串长度也0,则创造一个临时数组保存keyPath移除@“”对象要继又赋值给KeyPath。遍历结束晚,若这时KeyPath的Count大受1,则保留于propertyMeta中,并以propertyMeta保存在前新建的但是变数组keyPathPropertyMetas中,随后判断mapper[mappedToKey](mapper,之前创建的用来投的可转换字典)是否有价,没有则赋值空,有就是赋值给propertyMeta的_next,而后保存propertyMeta。

若值是NSArray类型,则拿其强转成NSArray类型而继字符串oneKey遍历,遍历前创办一个而变数组mappedToKeyArray,如果遍历时oneKey不是字符串或长也0虽然结束此次遍历,如果还未吻合则经过“。”分割成一个屡组,若数组的数超出1则保存数组否则保存oneKey,而后判断若propertyMeta->_mappedToKey不存在则保留其为oneKey,如果数组数量超出1虽保留_mappedToKeyPath为数组,若保存失败则return,随后保存mappedToKeyArray为_mappedToKeyArray等。

处理完定制属性之后还去遍历保存的具有Property元素的不过变换字典allPropertyMetas,保存字典的Value值的积极分子变量并保存Value值
为mapper[name],若保存成功则保留mapper,而后保存classInfo,所有property元素的个数,通过自定义强制内联方法ADClassGetNSType保存Cls的型,而后保存几独用户从定义方法的归值,代码中生详尽文档翻译。而继归self,就以此initWithClass方法了。

此时赶回到metaWithClass中,我们都沾了急需之meta,若得成功则线程信号量wait一破操作,并安装其价到缓存中,随后信号量加1返回Meta.

这时候回去到ad_modelWithDictionary方法被,我们曾获了modelMeta,若那_hasCustomClassFromDictionary值为YES就深受Cls执行同一不善+
(nullable Class)modelCustomClassForDictionary:(NSDictionary
*)dictionary;(通过字典创建的class,nil指利用时class,用户从定义的计),而后通过Cls创键一个靶one,让One执行方式-(BOOL)ad_modelSetWithDictionary:(NSDictionary
*)dic ; 若执行成功返回one否则为nil

-(BOOL)ad_modelSetWithDictionary:(NSDictionary *)dic ; 

以此方式也是下次当解说吧

至此Json转Model分析了。撒花~~~~

点自己入Git下充斥 真的,顺手给颗star吧,你的支撑用凡自我坚持的动力。