一.结构分析
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
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 会节省很大的开销。