1、位运算
在添加KVO时,配置参数可以通过按位或传入:
[self addObserver:self forKeyPath:@"Title" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
在内部拿到的是按位或运算的结果,如果在这个结果中找出传入了那些数据?
自定义一个枚举,和setOpitions方法:
typedef enum {
OptionsOne = 1<<0,
OptionsTwo = 1<<1,
OptionsThree = 1<<2
} Options;
- (void)setOpitions:(Options)options;
*1<<2 代表1向前移动2位,即0b 0000 0100
观察OptionsOne、OptionsTwo、OptionsThree按位或运算的结果:
0b 0000 0001 // OptionsOne,最后一位是1
0b 0000 0010 // OptionsTwo,倒数第二位是1
| 0b 0000 0100 // OptionsThree,倒数第三位是1
----------------
0b 0000 0111 // options,最后一位是1
最后三个option的数据都保存在了options里面。
如果想从结果中判断是否包含某个option,可以使用按位与运算来判断:
0b 0000 0111 // options,最后三位是1
& 0b 0000 0001 // OptionsOne,最后一位是1
----------------
0b 0000 0001 // 结果,最后一位是1
可以发现,OptionsOne通过和options进行与运算结果还是OptionsOne,这样就能判断options是否包含某个元素,setOptions方法内部可以这样判断:
- (void)setOpitions:(Options)options {
if (OptionsOne & options) {
// 包含OptionsOne
}
if (OptionsTwo & options) {
// 包含OptionsTwo
}
if (OptionsThree & options) {
// 包含OptionsThree
}
}
2、isa位域详解
// isa共用体(arm64&真机,简化后)
union isa_t {
uintptr_t bits;
Class cls;
struct {
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t unused : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
};
};
nonpointer
0,代表普通的指针,存储着Class、Meta-Class对象的内存地址
1,代表优化过,使用位域存储更多的信息
has_assoc
是否有设置过关联对象,如果没有,释放时会更快
has_cxx_dtor
是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快
shiftcls
存储着Class、Meta-Class对象的内存地址信息
magic
用于在调试时分辨对象是否未完成初始化
weakly_referenced
是否有被弱引用指向过,如果没有,释放时会更快
deallocating
对象是否正在释放
extra_rc
里面存储的值是引用计数器减1
has_sidetable_rc
引用计数器是否过大无法存储在isa中
如果为1,那么引用计数会存储在一个叫SideTable的类的属性中