& 运算
1>>0
1>>1
1>>2
1>>3
相当于将1 0b 0000 0001,= 1
如果左移1为,会变为 0b 0000 0010,= 2
左移2,会变为 0b 0000 0100, = 8
如果需要取出里面的值,就通过按位&,即用1 ,0000 0001 与传进来的值进行&,如果得到的结果不是0,就代表传进来是对应的值
NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
[_webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
这个里面的或,其实就是将 0000 0001 和 0000 0010 进行或运算,得到的结果就是 0000 0011,这样在通过上面的方式进行&运算的时候,就能将这两个都能取出来了,这个前提就是对应的值必须要设置的巧妙
union
共用体,就代表里面的东西是公用一块内存
union {
char *bits;
struct {
int age:1;
int no:1;
int hev:1;
}
}
这个共用体总共只占用了4个字节,其中bits是4个字节,struct里面的冒号代表的是“位域”,即age,no,hev都只占用了一个自己,总共只占用了3个,因为共用内存,所以总共占用了4个字节
arm-64之后,isa指针升级,用的就是union
- 所有类对象,元类对象地址的后3位都是0
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
没有直接的isa指针了
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
void setData(class_rw_t *newData)
{
ASSERT(!data() || (newData->flags & (RW_REALIZING | RW_FUTURE)));
// Set during realization or construction only. No locking needed.
// Use a store-release fence because there may be concurrent
// readers of data and data's contents.
uintptr_t newBits = (bits & ~FAST_DATA_MASK) | (uintptr_t)newData;
atomic_thread_fence(memory_order_release);
bits = newBits;
}
// Get the class's ro data, even in the presence of concurrent realization.
// fixme this isn't really safe without a compiler barrier at least
// and probably a memory barrier when realizeClass changes the data field
const class_ro_t *safe_ro() {
class_rw_t *maybe_rw = data();
if (maybe_rw->flags & RW_REALIZED) {
// maybe_rw is rw
return maybe_rw->ro();
} else {
// maybe_rw is actually ro
return (class_ro_t *)maybe_rw;
}
}
通过bit & FAST_DATA_MASK 来获得class_rw_t,
在通过class_rw_t 获得
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize;
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name;
method_list_t * baseMethodList;
protocol_list_t * baseProtocols;
const ivar_list_t * ivars;
const uint8_t * weakIvarLayout;
里面就可以获取到methodlist,ivars,protocols等类的具体信息
method
方法需要通过一层层的查找(isa-》类对象-〉元类对象)
如果方法存储在元类对象,每次都要遍历查找,就会很耗时
所以方法有缓存
cache_t cache;
struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
explicit_atomic<struct bucket_t *> _buckets;
explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
explicit_atomic<uintptr_t> _maskAndBuckets;
mask_t _mask_unused;
里面的_buckets 是散列表(哈希表)
每调用一个方法,就会往里面加入一个方法
_maskAndBuckets 为散列表长度-1,
_mask_unused 表示已经存储的个数
散列表的存储,是通过@selector(xxx)与 _maskAndBuckets 做& ,获得一个索引,然后直接将IMP存储在这个索引下,如果算的这个索引下有东西了,就将索引减1,得到下一个位置,如果等于0了,那么索引就等于_maskAndBuckets,如果存储的个数超过了散列表本身的大小(一般初始大小是4),就清空整个散列表,然后对散列表进行扩容,在插入刚刚的方法
哈希表,就是通过传进来的值与一个特定的值通过算法获取索引,这样会导致空间的浪费,就是通过空间来换取时间的存储方式,但是查询速度会加快
下面是一些位的意思
位 名称 意义
1 bit indexed 0 is raw isa, 1 is non-pointer isa.
1 bit has_assoc 对象拥有或者曾经拥有一个相关的参考。对象没有关联的引用可以释放的更快。
1 bit has_cxx_dtor 对象有一个 C++或者 ARC 的析构函数。没有析构函数的对象可以被释放的更快
30 bit shiftcls 类指针的非零位 Class pointer's non-zero bits.
9 bit magic 等于 0xd2。被调试器用来从没初始化的东西中区分真是的对象
1 bit weakly_referenced 对象正被或者曾经被一个自动释放的弱引用变量指向。没有被弱引用的对象能够释放的更快。
1 bit deallocating 对象正在被释放
1 bit has_sidetable_rc 对象引用计数过大无法被 store inline
19 bit extra_rc 对象的引用计数是extra_rc 值+1(举例,如果 extra_rc 是5,那么对象的真是引用计数是6)
网友评论