YYKit 源码解析
2017-02-27 本文已影响0人
DK_Azp
最近看了YYKit的代码集合,先看下ibireme大神(郭曜源)自己的介绍:
YYKit 详细介绍
YYKit 是一组庞大、功能丰富的 iOS 组件。
为了尽量复用代码,这个项目中的某些组件之间有比较强的依赖关系。为了方便其他开发者使用,我从中拆分出以下独立组件:
YYModel — 高性能的 iOS JSON 模型框架。
YYCache — 高性能的 iOS 缓存框架。
YYImage — 功能强大的 iOS 图像框架。
YYWebImage — 高性能的 iOS 异步图像加载框架。
YYText — 功能强大的 iOS 富文本框架。
YYKeyboardManager — iOS 键盘监听管理工具。
YYDispatchQueuePool — iOS 全局并发队列管理工具。
YYAsyncLayer — iOS 异步绘制与显示的工具。
YYCategories — 功能丰富的 Category 类型工具库。
1、YYModel — 高性能的 iOS JSON 模型框架。
1.知识储备
1.1 CFMutableDictionaryRef
CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks);
/*!
苹果官方定义:CFDictionaryCreateMutable 是CoreFoudation框架里面生成可变Dictionary的方法,
在YYModel框架中大量使用CoreFoudation框架的语句,相比于Foundation框架来说这样做可以提高框架的运行速度。
@function CFDictionaryCreateMutable
Creates a new mutable dictionary.
// 本方法用来生成一个新的可变字典
@param allocator The CFAllocator which should be used to allocate
memory for the dictionary and its storage for values. This
parameter may be NULL in which case the current default
CFAllocator is used. If this reference is not a valid
CFAllocator, the behavior is undefined.
// 第一个参数,用来为字典分配内存和本字典所要存储的Valuse
@param capacity A hint about the number of values that will be held
by the CFDictionary. Pass 0 for no hint. The implementation may
ignore this hint, or may use it to optimize various
operations. A dictionary's actual capacity is only limited by
address space and available memory constraints). If this
parameter is negative, the behavior is undefined.
// 意思是在创建字典的时候,设置默认的Values数目,可能会通过这个数目来分配具体的内存空间,
如果设为0 的时候,在实现的时候回忽略这个参数,一个字典的实际容量取决于这个字典的地址空间,和可用的内存限制。
@param keyCallBacks A pointer to a CFDictionaryKeyCallBacks structure
initialized with the callbacks for the dictionary to use on
each key in the dictionary. A copy of the contents of the
callbacks structure is made, so that a pointer to a structure
on the stack can be passed in, or can be reused for multiple
dictionary creations. If the version field of this
callbacks structure is not one of the defined ones for
CFDictionary, the behavior is undefined. The retain field may
be NULL, in which case the CFDictionary will do nothing to add
a retain to the keys of the contained values. The release field
may be NULL, in which case the CFDictionary will do nothing
to remove the dictionary's retain (if any) on the keys when the
dictionary is destroyed or a key-value pair is removed. If the
copyDescription field is NULL, the dictionary will create a
simple description for a key. If the equal field is NULL, the
dictionary will use pointer equality to test for equality of
keys. If the hash field is NULL, a key will be converted from
a pointer to an integer to compute the hash code. This callbacks
parameter itself may be NULL, which is treated as if a valid
structure of version 0 with all fields NULL had been passed in.
Otherwise, if any of the fields are not valid pointers to
functions of the correct type, or this parameter is not a
valid pointer to a CFDictionaryKeyCallBacks callbacks structure,
the behavior is undefined. If any of the keys put into the
dictionary is not one understood by one of the callback functions
the behavior when that callback function is used is undefined.
// 意思是:这个参数是指向一个称为CFDictionaryKeyCallBacks结构体的指针操作,这个结构体用来
初始化这个字典的所有Key的回调函数,并且在这个函数进行retain操作时会增加这个字典的索引,若为NULL则不会增加任何参数,同样release(不为空)会减少这个字典的索引,否则将不会减少任何参数。
@param valueCallBacks A pointer to a CFDictionaryValueCallBacks structure
initialized with the callbacks for the dictionary to use on
each value in the dictionary. The retain callback will be used
within this function, for example, to retain all of the new
values from the values C array. A copy of the contents of the
callbacks structure is made, so that a pointer to a structure
on the stack can be passed in, or can be reused for multiple
dictionary creations. If the version field of this callbacks
structure is not one of the defined ones for CFDictionary, the
behavior is undefined. The retain field may be NULL, in which
case the CFDictionary will do nothing to add a retain to values
as they are put into the dictionary. The release field may be
NULL, in which case the CFDictionary will do nothing to remove
the dictionary's retain (if any) on the values when the
dictionary is destroyed or a key-value pair is removed. If the
copyDescription field is NULL, the dictionary will create a
simple description for a value. If the equal field is NULL, the
dictionary will use pointer equality to test for equality of
values. This callbacks parameter itself may be NULL, which is
treated as if a valid structure of version 0 with all fields
NULL had been passed in. Otherwise,
if any of the fields are not valid pointers to functions
of the correct type, or this parameter is not a valid
pointer to a CFDictionaryValueCallBacks callbacks structure,
the behavior is undefined. If any of the values put into the
dictionary is not one understood by one of the callback functions
the behavior when that callback function is used is undefined.
// 如上会增加或者减少字典对应的Values。
@result A reference to the new mutable CFDictionary.
*/
static dispatch_semaphore_t lock;
// 当并行执行的处理更新数据时,会产生数据不一
//致的情况,有的时候应用程序还会异常结束,如下代码示例,
//当使用全局队列来更新NSMurableArray对象,在执行后由
//内存错误导致应用程序一场结束的概率很高,此时应该使用
//Dispatch semaphore
- (void) test{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray * array = [NSMutableArray arrayWithCapacity:1000];
for (int i = 0;i <1000;++i) {
dispatch_async(queue, ^{
[array addObject:[NSNumber numberWithInt:i]];
});
}
NSLog(@"array = %@",array);
}
/*log 打印 -- 线程测试(1253,0x700000104000) malloc: error for object 0x7fade4016200: double free
set a breakpoint in malloc_error_break to debug
*/
//Dispatch semaphore 是持有技术的信号,当计数器为0 的时候等待,当计数器大于或者等于1的时候不等待。
###于是有下面的代码
- (void) testSemaphore{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/**
1、生成Dispatch Semaphore
2、Dispatch Semaphore的计数初始值设定为“1”。
3、保证可访问NsmutableArray类对象的线程同事保证只能有一个。
**/
dispatch_semaphore_t semap = dispatch_semaphore_create(1);
NSMutableArray * array = [NSMutableArray arrayWithCapacity:1000];
for (int i = 0;i <1000;++i) {
/*
1、等待Dispatch Semaphore
2、一直等待,直到Dispatch Semaphore计数器达到大于或者等于1
*/
dispatch_async(queue, ^{
dispatch_wait(semap, DISPATCH_TIME_FOREVER);
/*
1、由于Dispatch Semaphore的计数器达到大于等于1,所以将Dispatch Semaphore的计数器减1,Dispatch_semaphone_wait 函数执行返回。
2、执行到此时的Dispatch Semaphore 的计数值恒为 “0”。由于可访问NSmutabnleArray类对象的线程只有1个,因此可安全的进行更新。
*/
[array addObject:[NSNumber numberWithInt:i]];
});
/*
1、 排他控制处理结束,所以通过Dispatch_semphore_signal 函数将Dispatch Semphore的计数值加1。
2、 如果有通过Dispatch_Semaphore_wait 函数,等到Dispatch Semaphore的计数值增加的线程,就有最先等到的线程执行。
*/
dispatch_semaphore_signal(semap);
}
NSLog(@"array = %@",array);
}
###runtime 基础
## id
/// A pointer to an instance of a class.
typedef struct objc_object *id;
// 是一个指向一个类实例的指针,注意是类的实例。
## objc_object
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// objc_object会被转换成 C 的结构体,而在这个struct中有一个 isa 指针,指向它的类别 Class。
## objc_class
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
// 从中可知:一个object_class 也是一个struct,并且它也包含一个指向本类的指针 isa,并且有本类的父类,类名称,版本,信息,方法列表和协议裂变等。
###MetaClass
//Class 本身也有一个 isa 指针,指向的是它的 MetaClass。
//当对一个实例发送消息时(-开头的方法),会在该 instance 对应的类的 methodLists 里查找。
//当对一个类发送消息时(+开头的方法),会在该类的 MetaClass 的 methodLists 里查找。
//每个 Class 都有一个 isa 指针指向一个唯一的 Meta Class
//每一个 Meta Class 的 isa 指针都指向最上层的 Meta Class,即 NSObject 的 MetaClass,而最上层的 MetaClass 的 isa 指针又指向自己.
## Ivar
//定义对象的实例变量,包括类型和名字。
struct objc_ivar {
char *ivar_name OBJC2_UNAVAILABLE;
char *ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
}