為什么要使用union聯(lián)合體?
比如定義一個(gè)bool值變量需要8個(gè)字節(jié),其實(shí)僅僅使用這8個(gè)字節(jié)中的一個(gè)位就可以表達(dá)是或否的情況了,使用union就是充分利用每個(gè)字節(jié)的每一個(gè)位,節(jié)約空間。
本文主要介紹以下部分:
一. 自定義位運(yùn)算
二. 自定義位域運(yùn)算
三. 自定義聯(lián)合體
四. isa解析
一. 自定義位運(yùn)算
先看示例:
@interface Person : NSObject
- (void)setTall:(BOOL)tall;
- (void)setRich:(BOOL)rich;
- (void)setHandsome:(BOOL)handsome;
- (BOOL)isTall;
- (BOOL)isRich;
- (BOOL)isHandsome;
@end
#import "Person.h"
#define TallMask (1<<0)
#define RichMask (1<<1)
#define HandsomeMask (1<<2)
@interface Person()
{
char _tallRichHansome;
}
@end
@implementation Person
- (instancetype)init
{
if (self = [super init]) {
_tallRichHansome = 0b00000000;
}
return self;
}
- (void)setTall:(BOOL)tall
{
if (tall) {
_tallRichHansome |= TallMask;
} else {
_tallRichHansome &= ~TallMask;
}
}
- (BOOL)isTall
{
return !!(_tallRichHansome & TallMask);
}
- (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHansome |= RichMask;
} else {
_tallRichHansome &= ~RichMask;
}
}
- (BOOL)isRich
{
return !!(_tallRichHansome & RichMask);
}
- (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHansome |= HandsomeMask;
} else {
_tallRichHansome &= ~HandsomeMask;
}
}
- (BOOL)isHandsome
{
return !!(_tallRichHansome & HandsomeMask);
}
@end
- 上邊
get方法使用!!取反兩次是因?yàn)楂@取到的值可能是2、4、8,第一次取反變成0,再次取反變成1。
main函數(shù)調(diào)用
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *person = [[Person alloc] init];
person.rich = YES;
person.tall = NO;
person.handsome = NO;
NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHandsome);
}
return 0;
}
結(jié)果為:
tall:0 rich:1 hansome:0
二. 自定義位域運(yùn)算
Person.m修改如下:
#import "Person.h"
@interface Person()
{
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
} _tallRichHandsome;
}
@end
@implementation Person
- (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
- 上邊
get方法使用!!取反兩次是因?yàn)樵O(shè)置值為YES的時(shí)候二進(jìn)制是這樣的0b1,系統(tǒng)會(huì)自動(dòng)把這個(gè)數(shù)據(jù)變成0b11111111結(jié)果為-1,因?yàn)樵摂?shù)據(jù)不為0,所以取反就會(huì)變成0,再次取反就會(huì)變成1。
或者修改如下:
struct {
unsigned char tall : 1;
unsigned char rich : 1;
unsigned char handsome : 1;
} _tallRichHandsome;
即添加unsigned修飾符也可解決取值為-1的問(wèn)題。
-
tall 、rich 、 handsome會(huì)從右至左各占一位。
三. 自定義聯(lián)合體
Person.m修改如下:
#import "Person.h"
#define TallMask (1<<0)
#define RichMask (1<<1)
#define HandsomeMask (1<<2)
#define ThinMask (1<<3)
@interface Person()
{
union {
int bits;
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
char thin : 1;
};
} _tallRichHandsome;
}
@end
@implementation Person
- (void)setTall:(BOOL)tall
{
if (tall) {
_tallRichHandsome.bits |= TallMask;
} else {
_tallRichHandsome.bits &= ~TallMask;
}
}
- (BOOL)isTall
{
return !!(_tallRichHandsome.bits & TallMask);
}
- (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHandsome.bits |= RichMask;
} else {
_tallRichHandsome.bits &= ~RichMask;
}
}
- (BOOL)isRich
{
return !!(_tallRichHandsome.bits & RichMask);
}
- (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHandsome.bits |= HandsomeMask;
} else {
_tallRichHandsome.bits &= ~HandsomeMask;
}
}
- (BOOL)isHandsome
{
return !!(_tallRichHandsome.bits & HandsomeMask);
}
- (void)setThin:(BOOL)thin
{
if (thin) {
_tallRichHandsome.bits |= ThinMask;
} else {
_tallRichHandsome.bits &= ~ThinMask;
}
}
- (BOOL)isThin
{
return !!(_tallRichHandsome.bits & ThinMask);
}
@end
以下代碼完全是增強(qiáng)可讀性,刪除掉完全不會(huì)有任何影響。
struct {
char tall : 1;
char rich : 1;
char handsome : 1;
char thin : 1;
};
通過(guò)上邊代碼的學(xué)習(xí),就可以讀懂OC底層isa指針的具體含義了。
四. isa解析
在arm64架構(gòu)之前,isa就是一個(gè)普通的指針,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址
從arm64架構(gòu)開(kāi)始,對(duì)isa進(jìn)行了優(yōu)化,變成了一個(gè)共用體(union)結(jié)構(gòu),還使用位域來(lái)存儲(chǔ)更多的信息
union isa_t {
Class cls;
uintptr_t bits;
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
};
};
isa內(nèi)部的位含義
nonpointer
0,代表普通的指針,存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址
1,代表優(yōu)化過(guò),使用位域存儲(chǔ)更多的信息has_assoc
是否有設(shè)置過(guò)關(guān)聯(lián)對(duì)象,如果沒(méi)有,釋放時(shí)會(huì)更快has_cxx_dtor
是否有C++的析構(gòu)函數(shù)(.cxx_destruct),如果沒(méi)有,釋放時(shí)會(huì)更快shiftcls
存儲(chǔ)著Class、Meta-Class對(duì)象的內(nèi)存地址信息magic
用于在調(diào)試時(shí)分辨對(duì)象是否未完成初始化weakly_referenced
是否有被弱引用指向過(guò),如果沒(méi)有,釋放時(shí)會(huì)更快
deallocating
對(duì)象是否正在釋放extra_rc
里面存儲(chǔ)的值是引用計(jì)數(shù)器減1has_sidetable_rc
引用計(jì)數(shù)器是否過(guò)大無(wú)法存儲(chǔ)在isa中
如果為1,那么引用計(jì)數(shù)會(huì)存儲(chǔ)在一個(gè)叫SideTable的類(lèi)的屬性中