博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
YYModel 源码解读(二)之YYClassInfo.h (3)
阅读量:5077 次
发布时间:2019-06-12

本文共 9043 字,大约阅读时间需要 30 分钟。

前边3篇介绍了YYClassinfo 文件的组成单元,算是功能的分割,按照业务的设计思想来说,方向应该是相反的

由此引申出我们在设计api的思想其实和项目管理是很类似的----- 一些题外话

1.目的

回到代码,首先应该明确写这个类的目的是什么? 按照正常逻辑,我们需要一个类来获取我们所需要的所有和此类相关的信息

包括(类名,父类,成员变量,方法,属性...)

2.技术调研

调研我们所需要的结果是否能够通过技术手段实现

3.目标分隔,也就是任务分解

需要把整体目标分解成小目标,在本代码中则分割成 三个部分

①获取IVar   -----> 具体的实现

②获取Method   -----> 具体的实现

③获取Property  ------> 具体的实现

好了大概的思想就是上边这些了 ,接下来让我们看看暴露出来的属性是怎么样的,也就是我们所需要的信息是什么

1 /** 2  Class information for a class. 3  */ 4 @interface YYClassInfo : NSObject 5 @property (nonatomic, assign, readonly) Class cls; ///< class object 6 @property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object 7 @property (nullable, nonatomic, assign, readonly) Class metaCls;  ///< class's meta class object 8 @property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class 9 @property (nonatomic, strong, readonly) NSString *name; ///< class name10 @property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info11 @property (nullable, nonatomic, strong, readonly) NSDictionary
*ivarInfos; ///< ivars12 @property (nullable, nonatomic, strong, readonly) NSDictionary
*methodInfos; ///< methods13 @property (nullable, nonatomic, strong, readonly) NSDictionary
*propertyInfos; ///< properties14 15 /**16 If the class is changed (for example: you add a method to this class with17 'class_addMethod()'), you should call this method to refresh the class info cache.18 19 After called this method, `needUpdate` will returns `YES`, and you should call 20 'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.21 */22 - (void)setNeedUpdate;23 24 /**25 If this method returns `YES`, you should stop using this instance and call26 `classInfoWithClass` or `classInfoWithClassName` to get the updated class info.27 28 @return Whether this class info need update.29 */30 - (BOOL)needUpdate;31 32 /**33 Get the class info of a specified Class.34 35 @discussion This method will cache the class info and super-class info36 at the first access to the Class. This method is thread-safe.37 38 @param cls A class.39 @return A class info, or nil if an error occurs.40 */41 + (nullable instancetype)classInfoWithClass:(Class)cls;42 43 /**44 Get the class info of a specified Class.45 46 @discussion This method will cache the class info and super-class info47 at the first access to the Class. This method is thread-safe.48 49 @param className A class name.50 @return A class info, or nil if an error occurs.51 */52 + (nullable instancetype)classInfoWithClassName:(NSString *)className;

这里需要注意的是两个方法

1 /**2  If the class is changed (for example: you add a method to this class with3  'class_addMethod()'), you should call this method to refresh the class info cache.4  5  After called this method, `needUpdate` will returns `YES`, and you should call 6  'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.7  */8 - (void)setNeedUpdate;

当使用运行时对本类 操作的时候 ,需要调用方法更新本类的信息,这个时候

1 needUpdate

将返回为yes 让后调用

`classInfoWithClass` or `classInfoWithClassName`

具体的作用后边还会详细的解释,接下来看看方法的具体实现

1 + (instancetype)classInfoWithClass:(Class)cls { 2      3     // 判空 4     if (!cls) return nil; 5     /** 6      *   在此使用了coreFoundation 的 CFMutableDictionaryRef 7      *   单例模式 8      */ 9     10     static CFMutableDictionaryRef classCache;11     static CFMutableDictionaryRef metaCache;12     static dispatch_once_t onceToken;13     /**14      *  GCD 信号15      */16     static dispatch_semaphore_t lock;17     dispatch_once(&onceToken, ^{18         classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);19         metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);20         lock = dispatch_semaphore_create(1);21     });22     23     // 加锁24     dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);25     26     /**27      *  首先在缓存中取值,分为两种,metaCache , classCache28      */29     YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));30     /**31      *  如果存在且需要更新,就更新32      */33     if (info && info->_needUpdate) {34         [info _update];35     }36     dispatch_semaphore_signal(lock);37     38     // 不存在,就要创建39     if (!info) {40         info = [[YYClassInfo alloc] initWithClass:cls];41         if (info) {42             dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);43             CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));44             dispatch_semaphore_signal(lock);45         }46     }47     return info;48 }

 

上边的代码用到了几个我们平时可能不太熟悉的东西,

总体来说,但凡是需要反复使用的东西,尽量做缓存操作,这应该算是一种思想吧

dispatch_semaphore_t

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 如果semaphore计数大于等于1.计数-1,返回,程序继续运行。

如果计数为0,则等待。

这里设置的等待时间是一直等待。dispatch_semaphore_signal(semaphore);计数+1

.在这两句代码中间的执行代码,每次只会允许一个线程进入,这样就有效的保证了在多线程环境下,只能有一个线程进入

这样就可以当做同步锁来使用了 。

CoreFoundation 框架的简单介绍

Core Foundation 是由oc base foundation 概念上衍生出来的一个库,只提供有限的基于C语言的oc的部分对象,

优点是 可以在frameworks and libraries 共享数据,使用coreFoundation 可以osX ios 运行

在平时使用中,我们可能更加关心的是

Toll-Free Bridged

也就是CF 和 NS 的转换问题

Objective-C 的ARC 内存管理 只管理 oc 的对象,对core foundation 是无效的,core foundation 必须通过 CFRelease来释放

对于MRC 可以直接进行转换,下面我们讨论 ARC 下的转换情况

1 id obj = [[NSObject alloc] init];2 void *p = obj;

系统会直接报错,错误信息为

1 Implicit conversion of Objective-C pointer type 'id' to C pointer type 'void *' requires a bridged cast

很明显 ,需要一个bridged 来辅助转换

1 id obj = [[NSObject alloc] init];2 void *p = (__bridge void *)obj;

ok,成功了 ,其实与这个bridged 相关的还有另外两个

__bridge_retained__bridge_transfer
__bridge只是单纯地执行了类型转换,没有进行所有权的转移,也就是说,当string对象被释放的时候,cfString也不能被使用了。
__bridge_retained 可以通过转换目标处(cfString)的 retain 处理,来使所有权转移。即使 string 变量被释放,cfString 还是可以使用具体的对象。只是有一点,由于Core Foundation的对象不属于ARC的管理范畴,所以需要自己release。
__bridge_transfer所有权被转移的同时,被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候,会经常用到 __bridge_transfer 关键字。
CFStringRef cfString = CFStringCreate...();NSString *string = (__bridge_transfer NSString *)cfString; // CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权,所以不需要调用 release
CFTypeRef  CFBridgingRetain(id  X)  {    return  (__bridge_retained  CFTypeRef)X;} id  CFBridgingRelease(CFTypeRef  X)  {    return  (__bridge_transfer  id)X;}

其他两个初始化方法

1 - (instancetype)initWithClass:(Class)cls { 2     if (!cls) return nil; 3     self = [super init]; 4     _cls = cls; 5     _superCls = class_getSuperclass(cls); 6     _isMeta = class_isMetaClass(cls); 7     if (!_isMeta) { 8         _metaCls = objc_getMetaClass(class_getName(cls)); 9     }10     _name = NSStringFromClass(cls);11     [self _update];12 13     _superClassInfo = [self.class classInfoWithClass:_superCls];14     return self;15 }
1 + (instancetype)classInfoWithClassName:(NSString *)className {2     Class cls = NSClassFromString(className);3     return [self classInfoWithClass:cls];4 }

与needUpdate 想关

1 - (void)setNeedUpdate {2     _needUpdate = YES;3 }4 5 - (BOOL)needUpdate {6     return _needUpdate;7 }
1 - (void)_update { 2     _ivarInfos = nil; 3     _methodInfos = nil; 4     _propertyInfos = nil; 5      6     Class cls = self.cls; 7     unsigned int methodCount = 0; 8     Method *methods = class_copyMethodList(cls, &methodCount); 9     if (methods) {10         NSMutableDictionary *methodInfos = [NSMutableDictionary new];11         _methodInfos = methodInfos;12         for (unsigned int i = 0; i < methodCount; i++) {13             YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];14             if (info.name) methodInfos[info.name] = info;15         }16         free(methods);17     }18     unsigned int propertyCount = 0;19     objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);20     if (properties) {21         NSMutableDictionary *propertyInfos = [NSMutableDictionary new];22         _propertyInfos = propertyInfos;23         for (unsigned int i = 0; i < propertyCount; i++) {24             YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];25             if (info.name) propertyInfos[info.name] = info;26         }27         free(properties);28     }29     30     unsigned int ivarCount = 0;31     Ivar *ivars = class_copyIvarList(cls, &ivarCount);32     if (ivars) {33         NSMutableDictionary *ivarInfos = [NSMutableDictionary new];34         _ivarInfos = ivarInfos;35         for (unsigned int i = 0; i < ivarCount; i++) {36             YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];37             if (info.name) ivarInfos[info.name] = info;38         }39         free(ivars);40     }41     42     if (!_ivarInfos) _ivarInfos = @{};43     if (!_methodInfos) _methodInfos = @{};44     if (!_propertyInfos) _propertyInfos = @{};45     46     _needUpdate = NO;47 }

 

转载于:https://www.cnblogs.com/machao/p/5558672.html

你可能感兴趣的文章
HDU 5458 Stability
查看>>
左手坐标系和右手坐标系
查看>>
solr后台操作Documents之增删改查
查看>>
http://yusi123.com/
查看>>
文件文本的操作
查看>>
Ubuntu linux下gcc版本切换
查看>>
记一次Web服务的性能调优
查看>>
Linux常用命令大全
查看>>
jQuery.form.js使用
查看>>
(转)linux sort,uniq,cut,wc命令详解
查看>>
关于ExecuteNonQuery执行的返回值(SQL语句、存储过程)
查看>>
UVa540 Team Queue(队列queue)
查看>>
mysql数据增删改查
查看>>
shell中下载最新版本或指定版本的办法(Dockerfile 中通用)
查看>>
极客时间-左耳听风-程序员攻略-分布式架构工程设计
查看>>
akka之种子节点
查看>>
不知道做什么时
查看>>
matlab 给某一列乘上一个系数
查看>>
密码学笔记——培根密码
查看>>
Screening technology proved cost effective deal
查看>>