YYModel 源码解读(二)之YYClassInfo.h (2)
/**
Instance variable information.
*/
@interface YYClassIvarInfo : NSObject
@property (nonatomic, assign, readonly) Ivar ivar; ///< ivar opaque struct
@property (nonatomic, strong, readonly) NSString *name; ///< Ivar's name
@property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding
@property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type /**
Creates and returns an ivar info object. @param ivar ivar opaque struct
@return A new object, or nil if an error occurs.
*/
- (instancetype)initWithIvar:(Ivar)ivar;
@end
上边代码通过创建Ivar(成员变量)的 抽象类, 返回我们需要的关于Ivar 的信息,
通过一个初始化方法创建,接下来我们看看该方法的具体实现
- (instancetype)initWithIvar:(Ivar)ivar {
// 初始化判空 如果为空 就返回nil
if (!ivar) return nil;
self = [super init];
_ivar = ivar;
// 获取成员变量的名称
const char *name = ivar_getName(ivar);
if (name) {
// 把c的字符串转化成oc的字符串
_name = [NSString stringWithUTF8String:name];
}
_offset = ivar_getOffset(ivar);
// 获取类型编码
const char *typeEncoding = ivar_getTypeEncoding(ivar);
if (typeEncoding) {
// 转为oc的字符穿
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
// 转成枚举值
_type = YYEncodingGetType(typeEncoding);
}
return self;
}
ivar_getName
ivar_getTypeEncoding
ivar_getOffset 这三个方法都是运行时方法,分别用来获取 名称 , 类型编码 , 偏移量 尤其要之处的是
ivar_getOffset方法: 官方文档中的描述是这样的
Returns the offset of an instance variable. Declaration
ptrdiff_t ivar_getOffset( Ivar ivar)
Discussion
For instance variables of type id or other object types, call object_getIvar and object_setIvar instead of using this offset to access the instance variable data directly.
ivar_getOffset函数,对于类型id或其它对象类型的实例变量,可以调用object_getIvar和object_setIvar来直接访问成员变量,而不使用偏移量。
接下来我们看看Method(方法)的 抽象类
/**
Method information.
*/
@interface YYClassMethodInfo : NSObject
@property (nonatomic, assign, readonly) Method method; ///< method opaque struct
@property (nonatomic, strong, readonly) NSString *name; ///< method name
@property (nonatomic, assign, readonly) SEL sel; ///< method's selector
@property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< method's parameter and return types
@property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type /**
Creates and returns a method info object. @param method method opaque struct
@return A new object, or nil if an error occurs.
*/
- (instancetype)initWithMethod:(Method)method;
@end
这这段代码中 比较陌生的是Method 和 IMP
Method 是一个结构体:
struct objc_method1.方法名:方法名为此方法的方法签名,相同函数名和参数的方法名是一样的
{
SEL method_name;
char * method_types;
IMP method_imp;
};
2.方法类型: 描述方法的参数类型
3. 方法真实实现代码块的地址指针,可像C 一样直接调用
- (instancetype)initWithMethod:(Method)method {
if (!method) return nil;
self = [super init];
_method = method;
// Method获取方法的名称
_sel = method_getName(method);
// 方法的实现地址
_imp = method_getImplementation(method);
// SEL 获取方法名
const char *name = sel_getName(_sel);
if (name) {
_name = [NSString stringWithUTF8String:name];
}
// 获取类型
const char *typeEncoding = method_getTypeEncoding(method);
if (typeEncoding) {
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
}
// 获取返回值类型
char *returnType = method_copyReturnType(method);
if (returnType) {
_returnTypeEncoding = [NSString stringWithUTF8String:returnType];
// 但凡 通过copy retain alloc 系统方法得到的内存,必须使用relea() 或 free() 进行释放
free(returnType);
}
// 获取参数列表
unsigned int argumentCount = method_getNumberOfArguments(method);
if (argumentCount > ) {
NSMutableArray *argumentTypes = [NSMutableArray new];
for (unsigned int i = ; i < argumentCount; i++) {
// 获取参数中的某一个参数
char *argumentType = method_copyArgumentType(method, i);
NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
[argumentTypes addObject:type ? type : @""];
if (argumentType) free(argumentType);
}
_argumentTypeEncodings = argumentTypes;
}
return self;
}
上边的代码使用了运行时中 关于Method 的一些方法,再次不做介绍,但值得注意的是
但凡 通过copy retain alloc 系统方法得到的内存,必须使用relea() 或 free() 进行释放
/**
Property information.
*/
@interface YYClassPropertyInfo : NSObject
@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct
@property (nonatomic, strong, readonly) NSString *name; ///< property's name
@property (nonatomic, assign, readonly) YYEncodingType type; ///< property's type
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
@property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name
@property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil
@property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull)
@property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull) /**
Creates and returns a property info object. @param property property opaque struct
@return A new object, or nil if an error occurs.
*/
- (instancetype)initWithProperty:(objc_property_t)property;
上边的类是对属性的抽象类,让我们通过下边的代码 了解下属性编码的知识
objc_property_t property = class_getProperty([YYWeiboStatus class], "user");
unsigned int num;
objc_property_attribute_t *attr = property_copyAttributeList(property, &num);
for (unsigned int i = ; i < num; i++) {
objc_property_attribute_t att = attr[i];
fprintf(stdout, "name = %s , value = %s \n",att.name , att.value);
}
const char *chars = property_getAttributes(property);
fprintf(stdout, "%s \n",chars);
打印的输出结果为
name = T , value = @"YYWeiboUser"
name = & , value =
name = N , value =
name = V , value = _user
T@"YYWeiboUser",&,N,V_user
可以看出,比较重要的是属性的编码都是以T开头 标示属性的类型 以V开头 标示属性的变量名
- (instancetype)initWithProperty:(objc_property_t)property {
if (!property) return nil;
self = [self init];
_property = property;
// 1. 获取属性名称
const char *name = property_getName(property);
if (name) {
_name = [NSString stringWithUTF8String:name];
}
// 2.获取每一个属性的编码字符串
YYEncodingType type = ;
unsigned int attrCount;
objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
// 3. 编译每一个属性的 objc_property_attribute_t
for (unsigned int i = ; i < attrCount; i++) {
// 3.1 根据objc_property_attribute_t 中的name 做一些事
switch (attrs[i].name[]) {
// T 代码属性的类型编码
case 'T': { // Type encoding
if (attrs[i].value) {
_typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
type = YYEncodingGetType(attrs[i].value);
// 计算属性的实体类型 比如:@"User"
if ((type & YYEncodingTypeMask) == YYEncodingTypeObject) {
size_t len = strlen(attrs[i].value); // len = 7
if (len > ) {
char name[len - ]; // 新建一个长度 = len - 2 的name字符数组 长度为5
name[len - ] = '\0'; // 设置最后一个字符为\0
memcpy(name, attrs[i].value + , len - ); // copy USer 到name 中,
// 获取name 的真实实体类型
_cls = objc_getClass(name);
}
}
}
} break;
case 'V': { // Instance variable
if (attrs[i].value) {
_ivarName = [NSString stringWithUTF8String:attrs[i].value];
}
} break;
case 'R': {
type |= YYEncodingTypePropertyReadonly;
} break;
case 'C': {
type |= YYEncodingTypePropertyCopy;
} break;
case '&': {
type |= YYEncodingTypePropertyRetain;
} break;
case 'N': {
type |= YYEncodingTypePropertyNonatomic;
} break;
case 'D': {
type |= YYEncodingTypePropertyDynamic;
} break;
case 'W': {
type |= YYEncodingTypePropertyWeak;
} break;
case 'G': { // getter 方法
type |= YYEncodingTypePropertyCustomGetter;
if (attrs[i].value) {
_getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
}
} break;
case 'S': { // setter 方法
type |= YYEncodingTypePropertyCustomSetter;
if (attrs[i].value) {
_setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
}
} // break; commented for code coverage in next line
default: break;
}
}
if (attrs) {
free(attrs);
attrs = NULL;
}
_type = type;
// 获取setter 和 getter 方法
if (_name.length) {
if (!_getter) {
_getter = NSSelectorFromString(_name);
}
if (!_setter) {
_setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:].uppercaseString, [_name substringFromIndex:]]);
}
}
return self;
}
最后让我来看看打印结果
objc_property_t property = class_getProperty([YYWeiboStatus class], "user");
YYClassPropertyInfo *propertyInfo = [[YYClassPropertyInfo alloc] initWithProperty:property];
NSLog(@"%@",propertyInfo.typeEncoding);
-- ::12.134 ModelBenchmark[:] @"YYWeiboUser"
typedef struct example {
int* aPint;
double aDouble;
char *aString;
int anInt;
BOOL isMan;
struct example *next;
} Example;
@property (nonatomic, assign) Example example;
-- ::59.493 ModelBenchmark[:] {example=^id*iB^{example}}
objc_property_t property = class_getProperty([YYWeiboStatus class], "statusID");
YYClassPropertyInfo *propertyInfo = [[YYClassPropertyInfo alloc] initWithProperty:property];
NSLog(@"%@",propertyInfo.typeEncoding);
-- ::39.747 ModelBenchmark[:] Q
到此 关于 Ivar Method Property 的抽象类已经介绍完毕,在后面的使用中 直接使用这些抽象类来进行编码的
YYModel 源码解读(二)之YYClassInfo.h (2)的更多相关文章
- YYModel 源码解读(二)之NSObject+YYModel.h (1)
本篇文章主要介绍 _YYModelPropertyMeta 前边的内容 首先先解释一下前边的辅助函数和枚举变量,在写一个功能的时候,这些辅助的东西可能不是一开始就能想出来的,应该是在后续的编码过程中 ...
- jQuery.Callbacks 源码解读二
一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...
- (转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
转自:http://www.baiyuxiong.com/?p=886 ---------------------------------------------------------------- ...
- YYModel 源码解读(二)之YYClassInfo.h (3)
前边3篇介绍了YYClassinfo 文件的组成单元,算是功能的分割,按照业务的设计思想来说,方向应该是相反的 由此引申出我们在设计api的思想其实和项目管理是很类似的----- 一些题外话 1.目的 ...
- YYModel 源码解读(一)之YYModel.h
#if __has_include(<YYModel/YYModel.h>) FOUNDATION_EXPORT double YYModelVersionNumber; FOUNDATI ...
- YYModel 源码解读 总结
在使用swfit写代码的过程中,使用了下oc写的字典转模型,发现有些属性转不成功,就萌生了阅读源码的想法. 其实一直都知道Runtime机制,但并没有系统的学习,可能是因为平时的使用比较少,无意间在g ...
- ConcurrentHashMap源码解读二
接下来就讲解put里面的三个方法,分别是 1.数组初始化方法initTable() 2.线程协助扩容方法helpTransfer() 3.计数方法addCount() 首先是数组初始化,再将源码之前, ...
- mybatis源码解读(二)——构建Configuration对象
Configuration 对象保存了所有mybatis的配置信息,主要包括: ①. mybatis-configuration.xml 基础配置文件 ②. mapper.xml 映射器配置文件 1. ...
- ROS源码解读(二)--全局路径规划
博客转载自:https://blog.csdn.net/xmy306538517/article/details/79032324 ROS中,机器人全局路径规划默认使用的是navfn包 ,move_b ...
- go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
nsqlookupd: 官方文档解释见:http://bitly.github.io/nsq/components/nsqlookupd.html 用官方话来讲是:nsqlookupd管理拓扑信息,客 ...
随机推荐
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 史上最详细git教程
题外话 虽然这个标题很惊悚,不过还是把你骗进来了,哈哈-各位看官不要着急,耐心往下看 Git是什么 Git是目前世界上最先进的分布式版本控制系统. SVN与Git的最主要的区别 SVN是集中式版本控制 ...
- 启用 Open vSwitch - 每天5分钟玩转 OpenStack(127)
Linux Bridge 和 Open vSwitch 是目前 OpenStack 中使用最广泛的两种虚机交换机技术. 前面各章节我们已经学习了如何用 Linux Bridge 作为 ML2 mech ...
- 玩转spring boot——开篇
很久没写博客了,而这一转眼就是7年.这段时间并不是我没学习东西,而是园友们的技术提高的非常快,这反而让我不知道该写些什么.我做程序已经有十几年之久了,可以说是彻彻底底的“程序老炮”,至于技术怎么样?我 ...
- 马里奥AI实现方式探索 ——神经网络+增强学习
[TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...
- 代码的坏味道(17)——夸夸其谈未来性(Speculative Generality)
坏味道--夸夸其谈未来性(Speculative Generality) 特征 存在未被使用的类.函数.字段或参数. 问题原因 有时,代码仅仅为了支持未来的特性而产生,然而却一直未实现.结果,代码变得 ...
- spring boot 实战:我们的第一款开源软件
在信息爆炸时代,如何避免持续性信息过剩,使自己变得专注而不是被纷繁的信息所累?每天会看到各种各样的新闻,各种新潮的技术层出不穷,如何筛选出自己所关心的? 各位看官会想,我们是来看开源软件的,你给我扯什 ...
- 水平可见直线 bzoj 1007
水平可见直线 (1s 128M) lines [问题描述] 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆 ...
- 《动手实现一个网页加载进度loading》
loading随处可见,比如一个app经常会有下拉刷新,上拉加载的功能,在刷新和加载的过程中为了让用户感知到 load 的过程,我们会使用一些过渡动画来表达.最常见的比如"转圈圈" ...
- 嵌入式&iOS:回调函数(C)与block(OC)回调对比
学了OC的block,再写C的回调函数有点别扭,对比下区别,回忆记录下. C的回调函数: callBack.h 1).定义一个回调函数的参数数量.类型. typedef void (*CallBack ...