Objective-C是一门动态性比较强的编程语言,跟C、C++等语言有着很大的不同
Objective-C的动态性是由Runtime API来支撑的
Runtime API提供的接口基本都是C语言的,源码由C\C++\汇编语言编写
一、isa详解
- 在arm64架构之前,isa就是一个普通的指针,存储着Class、Meta-Class对象的内存地址
-
从arm64架构开始,对isa进行了优化,变成了一个共用体(union)结构,还使用位域来存储更多的信息
二、位运算
mask 掩码
“& 与” 按位与运算 如果都是1 就输出1 ,如果不都是1 就输出0
0000 0111
& 0000 0001
-------------
0000 0001
tall 就是0000 0001 也就是1
rich 就是0000 0010 也就是2
handsome 就是0000 0100 也就是4
"| 或"按位或运算 如果是1 其他都是1
0000 0101
| 0000 0011
-------------
0000 0111
”~“按位取反
普通写法
#import "MJPerson.h"
// &可以用来取出特定的位
// 0000 0111
//&0000 0100
//------
// 0000 0100
// 掩码,一般用来按位与(&)运算的
//#define MJTallMask 1
//#define MJRichMask 2
//#define MJHandsomeMask 4
//#define MJTallMask 0b00000001
//#define MJRichMask 0b00000010
//#define MJHandsomeMask 0b00000100
#define MJTallMask (1<<0) // 1左移0位
#define MJRichMask (1<<1) // 1左移1位
#define MJHandsomeMask (1<<2) // 1左移2位
@interface MJPerson()
{
char _tallRichHansome;
}
@end
@implementation MJPerson
// 0010 1010
//&1111 1101
//----------
// 0010 1000
- (instancetype)init
{
if (self = [super init]) {
_tallRichHansome = 0b00000100;
}
return self;
}
- (void)setTall:(BOOL)tall
{
if (tall) {
_tallRichHansome |= MJTallMask;
} else {
_tallRichHansome &= ~MJTallMask; // ~ 按位取反 不是|
}
}
- (BOOL)isTall
{
return !!(_tallRichHansome & MJTallMask);
}
- (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHansome |= MJRichMask;
} else {
_tallRichHansome &= ~MJRichMask;
}
}
- (BOOL)isRich
{
return !!(_tallRichHansome & MJRichMask);
}
- (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHansome |= MJHandsomeMask;
} else {
_tallRichHansome &= ~MJHandsomeMask;
}
}
- (BOOL)isHandsome
{
return !!(_tallRichHansome & MJHandsomeMask);
}
@end
结构体位域写法
// !!(_tallRichHansome & MJTallMask) 也可以不这么写,直接写(_tallRichHansome & MJTallMask),但是需要位域1改为2,也就是char rich : 2;
#import "MJPerson.h"
//#define MJTallMask (1<<0)
//#define MJRichMask (1<<1)
//#define MJHandsomeMask (1<<2)
@interface MJPerson()
{
// 位域
struct {
char tall : 1; // : 1 位域
char rich : 1;
char handsome : 1;
} _tallRichHandsome;
// 0x 0000 0000 先写的在后边 也就是tall在倒数第一个0,rich在倒数第二个0,handsome在倒数第三个0
}
@end
@implementation MJPerson
- (void)setTall:(BOOL)tall
{
_tallRichHandsome.tall = tall;
}
- (BOOL)isTall
{
return !!_tallRichHandsome.tall;
}
- (void)setRich:(BOOL)rich
{
_tallRichHandsome.rich = rich;
}
- (BOOL)isRich
{
return !!_tallRichHandsome.rich;
}
- (void)setHandsome:(BOOL)handsome
{
_tallRichHandsome.handsome = handsome;
}
- (BOOL)isHandsome
{
return !!_tallRichHandsome.handsome;
}
@end
union共用体写法
#import "MJPerson.h"
#define MJTallMask (1<<0)
#define MJRichMask (1<<1)
#define MJHandsomeMask (1<<2)
#define MJThinMask (1<<3)
@interface MJPerson()
{
union {
int bits;
struct { // 只是增加可读性,不会影响共用体所占字节大小,可以删掉
char tall : 4;
char rich : 4;
char handsome : 4;
char thin : 4;
};
} _tallRichHandsome;
}
@end
@implementation MJPerson
- (void)setTall:(BOOL)tall
{
if (tall) {
_tallRichHandsome.bits |= MJTallMask;
} else {
_tallRichHandsome.bits &= ~MJTallMask;
}
}
- (BOOL)isTall
{
return !!(_tallRichHandsome.bits & MJTallMask);
}
- (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHandsome.bits |= MJRichMask;
} else {
_tallRichHandsome.bits &= ~MJRichMask;
}
}
- (BOOL)isRich
{
return !!(_tallRichHandsome.bits & MJRichMask);
}
- (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHandsome.bits |= MJHandsomeMask;
} else {
_tallRichHandsome.bits &= ~MJHandsomeMask;
}
}
- (BOOL)isHandsome
{
return !!(_tallRichHandsome.bits & MJHandsomeMask);
}
- (void)setThin:(BOOL)thin
{
if (thin) {
_tallRichHandsome.bits |= MJThinMask;
} else {
_tallRichHandsome.bits &= ~MJThinMask;
}
}
- (BOOL)isThin
{
return !!(_tallRichHandsome.bits & MJThinMask);
}
@end
isa详解--位域
Class对象,Meta-Class对象最后三位地址值都是0
二、class结构
class_rw_t(可以更方便的区分分类跟类的信息)
class_ro_t
注:class_ro_t 存储类的基本信息 当有分类的时候 将当前的class_ro_t 数据跟分类的信息存储到class_rw_t中
method_t
Type Encoding
方法缓存(其实就是通过isa指针查找类或者元类对象里面的cache_t的bucket_t里面是否缓存了此方法)
散列表原理(通过key生成一个索引)
- 散列表也叫做哈希表是根据关键码值(Key value)而直接进行访问的[数据结构],也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做[散列函数]
1、如果是一个方法列表的话:方法名@selector(方法名)&_mask(也就是cache_t里面的mask_t)生成索引,其他位置都成NULL,牺牲内存空间换取执行效率
注:不论@selector的值怎么变,&_mask以后的值都会小于或者等于_mask的值,所以mask_t 是散列表的长度 - 1
2、如果是两个方法列表的话
3、如果两个方法缓存的索引值是一样的话,会将当前索引-1进行存储,如果有值的话 继续-1
取值的时候:先根据索引进行比较key是否是同一个key,如果是的话 直接取值,如果不是的话索引-1继续查找,如果索引为0的话 就去查找_mask 也就是数组的最后一个,重新继续查找
一开始的mask 是有大小的 不是从0开始的
注:哪一个对象调用了方法,就缓存到哪一个对象的cache里面
如果超出容量 新的容量=旧的容量 * 2 然后会清空旧的缓存,只存储新的缓存
网友评论