一、isa指针结构

union isa_t
{
isa_t() { }
isa_t(uintptr_t value) : bits(value) { } Class cls;
uintptr_t bits; #if SUPPORT_PACKED_ISA // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
// nonpointer must be the LSB (fixme or get rid of it)
// shiftcls must occupy the same bits that a real class pointer would
// bits + RC_ONE is equivalent to extra_rc + 1
// RC_HALF is the high bit of extra_rc (i.e. half of its range) // future expansion:
// uintptr_t fast_rr : 1; // no r/r overrides
// uintptr_t lock : 2; // lock for atomic property, @synch
// uintptr_t extraBytes : 1; // allocated with extra bytes # if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
struct {
uintptr_t nonpointer : ;
uintptr_t has_assoc : ;
uintptr_t has_cxx_dtor : ;
uintptr_t shiftcls : ; // MACH_VM_MAX_ADDRESS 0x1000000000
uintptr_t magic : ;
uintptr_t weakly_referenced : ;
uintptr_t deallocating : ;
uintptr_t has_sidetable_rc : ;
uintptr_t extra_rc : ;
# define RC_ONE (1ULL<<)
# define RC_HALF (1ULL<<)
}; # elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
struct {
uintptr_t nonpointer : ;
uintptr_t has_assoc : ;
uintptr_t has_cxx_dtor : ;
uintptr_t shiftcls : ; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
uintptr_t magic : ;
uintptr_t weakly_referenced : ;
uintptr_t deallocating : ;
uintptr_t has_sidetable_rc : ;
uintptr_t extra_rc : ;
# define RC_ONE (1ULL<<)
# define RC_HALF (1ULL<<)
}; # else
# error unknown architecture for packed isa
# endif // SUPPORT_PACKED_ISA
#endif #if SUPPORT_INDEXED_ISA # if __ARM_ARCH_7K__ >= # define ISA_INDEX_IS_NPI
# define ISA_INDEX_MASK 0x0001FFFC
# define ISA_INDEX_SHIFT
# define ISA_INDEX_BITS
# define ISA_INDEX_COUNT ( << ISA_INDEX_BITS)
# define ISA_INDEX_MAGIC_MASK 0x001E0001
# define ISA_INDEX_MAGIC_VALUE 0x001C0001
struct {
uintptr_t nonpointer : ;
uintptr_t has_assoc : ;
uintptr_t indexcls : ;
uintptr_t magic : ;
uintptr_t has_cxx_dtor : ;
uintptr_t weakly_referenced : ;
uintptr_t deallocating : ;
uintptr_t has_sidetable_rc : ;
uintptr_t extra_rc : ;
# define RC_ONE (1ULL<<)
# define RC_HALF (1ULL<<)
}; # else
# error unknown architecture for indexed isa
# endif // SUPPORT_INDEXED_ISA
#endif };

分析:

1.我们知道,实例对象的isa指针指向该对象所属类的类对象;类对象的isa指向其元类对象;

2.真机为arm64架构,模拟器和mac电脑为x86架架构,以下以arm64为例讲解;

3.在64位系统下,指针所占字节为8个即64位;

4.在arm64之前,isa就是一个普通的指针,存放着类(元类)对象的地址;之后,则需要&

ISA_MASK掩码,才能获取到类(元类)对象的地址,此时isa指针为一个共用体,存储的信息不局限于类(元类)对象的地址;

5.存储信息介绍:

其中,shiftcls结构体成员变量(33位)用来存储类(元类)对象的地址;

二、类(元类)对象的地址取值原理——位域

1.结构体支持位域运算

//代码

struct bs {
unsigned a : ;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
unsigned b : ;
unsigned c : ;
}bit, *pbit; void test1()
{
bit.a = ;//超过位域范围报警告
bit.b = ;
bit.c = ;
NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c); pbit=&bit;
pbit-> a=;
pbit-> b&=;
pbit-> c|=;
printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
}

//输出

-- ::37.051464+ SetAndGetsForMask[:] ,,
,,
Program ended with exit code:

//分析

1)unsigned即无符号整型,占4个字节;结构体中成员变量所占内存相互独立且连续;

2)以a为例,所占位数为9位即0b111111111(十进制511),所以a的取值范围0~511,如果是512(二进制0b1000000000),由于只取低9位(000000000),所以取出值为0;

3)按位与&:两个都为1运算结果为1,否则为0;按位或|:两个都为0运算结果为0,否则为1;

2.参照isa,共用体套用结构体,一个char字符(一个字节)存储多个BOOL值并制定存储位置

2.设置类属性BOOL值(setter and getter)

//Person

#import "Person.h"

//mask即掩码,表示二进制数(0b开头)
#define TallMask (1<<0) //表示1左移0位:0b 0000 0001
#define RichMask (1<<1) //表示1左移1位:0b 0000 0010
#define HandsomeMask (1<<2) //表示1左移2位:0b 0000 0100 //拓展:10<<3即在10对应的二进制数后添加3个0 @interface Person()
{
char _saveBox;
} @end @implementation Person - (instancetype)init
{
if (self = [super init]) {
//用一个字节来存储三个变量:从最右往左依次为Tall、Rich、Handsome
_saveBox = 0b00000101;
}
return self;
} /*思路
0000 0101(_saveBox)
|0000 0001(掩码)
---------
0000 0001(赋值tall为1) 0000 0101
&1111 1110(掩码取反)
---------
0000 0100(赋值tall为0) 1.如果赋的值为1,则按位或;
2.如果赋的值为0,则掩码先取反,后按位与;
*/
- (void)setTall:(BOOL)tall
{
if (tall) {
_saveBox |= TallMask;
} else {
_saveBox &= ~TallMask;
}
} - (void)setRich:(BOOL)rich
{
if (rich) {
_saveBox |= RichMask;
} else {
_saveBox &= ~RichMask;
}
} - (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_saveBox |= HandsomeMask;
} else {
_saveBox &= ~HandsomeMask;
}
} /*思路
0000 0101
&0000 0001
---------
0000 0001(取出tall值) 1.按位与,用掩码取出_saveBox中特定位;
2.结果>=1,取反为0,再取反为1;同理,为0则双取反后为0;
*/
- (BOOL)isTall
{
return !!(_saveBox & TallMask);
} - (BOOL)isRich
{
return !!(_saveBox & RichMask);
} - (BOOL)isHandsome
{
return !!(_saveBox & HandsomeMask);
} @end

//Student

#import "Student.h"

@interface Student()
{
/*思路
1.用一个结构体来存放变量;
2.结构体支持位域:按先后顺序,一个char字符一个字节(0b0000 0000),从最右至左依次为tall、rich、handsome;
*/
struct {
char tall : ;//用一位来存储
char rich : ;
char handsome : ;
}_tallRichHandsome;
} @end @implementation Student - (void)setTall:(BOOL)tall
{
_tallRichHandsome.tall = tall;
} - (void)setRich:(BOOL)rich
{
_tallRichHandsome.rich = rich;
} - (void)setHandsome:(BOOL)handsome
{
_tallRichHandsome.handsome = handsome;
} - (BOOL)isTall
{
return !!_tallRichHandsome.tall;//非0(包括负数)取反为0
} - (BOOL)isRich
{
return !!_tallRichHandsome.rich;
} - (BOOL)isHandsome
{
return !!_tallRichHandsome.handsome;
} @end

//Worker

#import "Worker.h"

#define TallMask (1<<0)//也可以左移6位,剩余位没用到
#define RichMask (1<<1)
#define HandsomeMask (1<<2)
#define ThinMask (1<<3) @interface Worker()
{
//苹果系统设计思路
union {
char bits;//一个字节存储结构体中的所有成员变量
struct {//摆设用:位域,增加可读性
char tall : ;//占一位
char rich : ;
char handsome : ;
char thin : ;
};
}_tallRichHandsome;
} @end @implementation Worker - (void)setTall:(BOOL)tall
{
if (tall) {
NSLog(@"----%c", _tallRichHandsome.bits);
_tallRichHandsome.bits |= TallMask;
} else {
_tallRichHandsome.bits &= ~TallMask;
}
} - (void)setRich:(BOOL)rich
{
if (rich) {
_tallRichHandsome.bits |= RichMask;
} else {
_tallRichHandsome.bits &= ~RichMask;
}
} - (void)setHandsome:(BOOL)handsome
{
if (handsome) {
_tallRichHandsome.bits |= HandsomeMask;
} else {
_tallRichHandsome.bits &= ~HandsomeMask;
}
} - (void)setThin:(BOOL)thin
{
if (thin) {
_tallRichHandsome.bits |= ThinMask;
} else {
_tallRichHandsome.bits &= ~ThinMask;
}
} - (BOOL)isTall
{
return !!(_tallRichHandsome.bits & TallMask);
} - (BOOL)isRich
{
return !!(_tallRichHandsome.bits & RichMask);
} - (BOOL)isHandsome
{
return !!(_tallRichHandsome.bits & HandsomeMask);
} - (BOOL)isThin
{
return !!(_tallRichHandsome.bits & ThinMask);
} @end

//main

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
#import "Worker.h"
#import "Engineer.h" struct bs {
unsigned a : ;//如果超过位域范围(511),则只取范围内的值,其他位(高位)丢弃
unsigned b : ;
unsigned c : ;
}bit, *pbit; void test1()
{
bit.a = ;//超过位域范围报警告
bit.b = ;
bit.c = ;
NSLog(@"%d,%d,%d\n", bit.a, bit.b, bit.c); pbit=&bit;
pbit-> a=;
pbit-> b&=;
pbit-> c|=;
printf("%d,%d,%d\n ",pbit-> a,pbit-> b,pbit-> c);
} void test2()
{
Person *per = [[Person alloc] init];
per.tall = NO;
per.rich = NO;
per.handsome = YES;
NSLog(@"%d %d %d", per.isTall, per.isRich, per.isHandsome);
} void test3()
{
Student *stu = [[Student alloc] init];
stu.tall = YES;
stu.rich = NO;
stu.handsome = YES;
NSLog(@"%d %d %d", stu.isTall, stu.isRich, stu.isHandsome);
} void test4()
{
Worker *worker = [[Worker alloc] init];
// worker.tall = YES;
worker.rich = NO;
worker.handsome = NO;
worker.thin = YES;
NSLog(@"%d %d %d", worker.isThin, worker.isRich, worker.isHandsome);
} void test5()
{
Engineer *engineer = [[Engineer alloc] init];
// engineer.age = 12;
// engineer.level = 6;
// engineer.workers = 5; //0b 1111 1111 1111 1111(十进制:65535)
//0b 0010 1100 1110 1101(十进制:11501)
engineer->_personalInfo.bits =;
NSLog(@"%d %d %d", engineer.getAge, engineer.getLevel, engineer.getWorkers);
//2019-10-08 16:42:09.612140+0800 SetAndGetsForMask[1488:127227] 7 16 8160
//
} int main(int argc, const char * argv[]) {
@autoreleasepool { test1();
// test2();
// test3();
// test4();
// test5();
}
return ;
}

//打印

-- ::04.998750+ SetAndGetsForMask[:]
-- ::04.999093+ SetAndGetsForMask[:]
-- ::04.999122+ SetAndGetsForMask[:]
Program ended with exit code:

//分析(以Worker为例)

1)共用体中所有成员共同占用一块内存区,其大小等于最大那个成员所占字节数;

2)Worker中的结构体并为定义变量,编译器不会计算其内存,仅是增加可读性;

3)Worker中只有一个char型变量bits(占一个字节),故该共用体变量_tallRichHandsome也占一个字节;

4)结构体的位域限制变量的取值范围(一位:即0或1),mask掩码规定该变量存储的位置(在哪一位上);

3.设置类属性非BOOL类型(setter and getter)——限定变量值范围且指定存储位置

//Engineer

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

//位域位置(变量值存储位置)
#define AgeMask 0b00000111//最低三位存储
#define LevelMask (1<<4)//低位往高位数,第5位存储
#define WorkersMask 0b0001111111100000 @interface Engineer : NSObject
{
@public
union {
int bits;
struct {//位域范围(变量值范围)
int age : ;
int level : ;
int workers : ;
};
}_personalInfo;
} //- (void)setAge:(int)age;
//- (void)setLevel:(int)level;
//- (void)setWorkers:(int)workers; - (int)getAge;
- (int)getLevel;
- (int)getWorkers; @end NS_ASSUME_NONNULL_END #import "Engineer.h" @implementation Engineer //- (void)setAge:(int)age
//{
// self->_personalInfo.bits |= AgeMask;
//}
//
//- (void)setLevel:(int)level
//{
// self->_personalInfo.bits |= LevelMask;
//}
//
//- (void)setWorkers:(int)workers
//{
// self->_personalInfo.bits |= WorkersMask;
//} - (int)getAge
{
return self->_personalInfo.bits & AgeMask;
} - (int)getLevel
{
return self->_personalInfo.bits & LevelMask;
} - (int)getWorkers
{
return self->_personalInfo.bits & WorkersMask;
} @end

//打印

-- ::14.617655+ SetAndGetsForMask[:]
Program ended with exit code:

//说明

1)掩码mask既可以直接用二进制(0b开头)或十六进制(0x开头)表示,也可以左移符号<<表示(一般用于位域为1的情况);

2)掩码表示所占位数:1表示占住该位,0未占;并且所占位数应当是连续的,不存在两侧为1,中间为0的情况;

三、按位或(叠加)

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = ,
UIViewAutoresizingFlexibleLeftMargin = << ,
UIViewAutoresizingFlexibleWidth = << ,
UIViewAutoresizingFlexibleRightMargin = << ,
UIViewAutoresizingFlexibleTopMargin = << ,
UIViewAutoresizingFlexibleHeight = << ,
UIViewAutoresizingFlexibleBottomMargin = <<
}; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin;

1.分析:在iOS中,对view的自动布局经常会用到上述代码,苹果的做法是定义个枚举且每种类型都只占不同的一个二进制位,按位或相当于设定的场景都要考虑到;

2.如下代码:

typedef enum{
YBOptionTypeNone = , //0b0000
YBOptionTypeOne = <<, //0b0001
YBOptionTypeTwo = <<, //0b0010
YBOptionTypeThree = <<, //0b0100
YBOptionTypeFour = << //0b1000
}YBOptionType; void test6(YBOptionType option)
{
/*按位或叠加(包含多种情况),按位与取出(获得特定情况)
0b0001
0b0100
| 0b1000
----------
0b1101
& 0b0100
----------
0b0100
*/
if (option & YBOptionTypeOne) {
NSLog(@"contain YBOptionTypeOne");
} if (option & YBOptionTypeTwo) {
NSLog(@"contain YBOptionTypeTwo");
} if (option & YBOptionTypeThree) {
NSLog(@"contain YBOptionTypeThree");
} if (option & YBOptionTypeFour) {
NSLog(@"contain YBOptionTypeFour");
}
} int main(int argc, const char * argv[]) {
@autoreleasepool { // test1();
// test2();
// test3();
// test4();
// test5();
test6(YBOptionTypeOne | YBOptionTypeThree | YBOptionTypeFour);
}
return ;
}

//打印

-- ::17.154998+ SetAndGetsForMask[:] contain YBOptionTypeOne
-- ::17.155318+ SetAndGetsForMask[:] contain YBOptionTypeThree
-- ::17.155332+ SetAndGetsForMask[:] contain YBOptionTypeFour
Program ended with exit code:

四、结论

1.arm64之后,isa是一个共用体类型的指针,存储内部套用的结构体中的所有成员变量;

2.根据结构体的位域来限制成员变量的值范围,用掩码来规定成员变量存储的位置,对掩码按位与运算取出特定位置的成员变量的值;

如:用bits对ISA_MASK按位与运算后,得到的是类(元类)对象的地址;

可以看到shiftcls成员变量位域为33位,所占bits变量的存储位置为:地位到高位第四位起,最低三位是空出来的

————因此,在arm64架构中,所有的类和元类对象地址二进制表示时最低三位都为0,十六进制表示时最低一位为0或8(这个用class和object_getClass去打印地址,此处不再展示了)!

3.按位与作用为在集合中取出某个特定值,按位或则将若干个特定值集合到一个值中(即所有设定场景都要考虑到);

拓展:

//代码

//计算器演示

//分析

1.模拟器为x86_64架构,64位指针占八个字节;在结构体中,自上而下的变量在isa中的存储位置为从低位到高位即计算器中下到上、左到右——这点应该没问题;

2.per实例对象曾经被弱指针指向过(现在释放了),且曾经关联过对象(现在置空),而对应的位为1即表示确实曾经被弱指针指向过(如果没有则会为0),曾经关联过对象;所以

has_assoc和weakly_referenced分别表示对象曾经被弱指针指向过和曾经关联过对象——其他变量分析以此类推;

GitHub

最新文章

  1. 程序员遇到BUG的解释
  2. SSL/TLS 高强度加密: 常见问题解答
  3. Repeater 使用方法
  4. vim中.swp文件处理
  5. SpringMVC学习总结(二)——DispatcherServlet详解
  6. json解析日期方法 问题的解决方案
  7. Chrome浏览器插件VisualEvent,可以方便的查看页面绑定的事件
  8. Python中classmethod与staticmethod区别
  9. 安装 Kali Linux 后需要做的 20 件事
  10. yaf代码生成工具的使用
  11. XV Open Cup named after E.V. Pankratiev. GP of America
  12. HDU-1421 搬寝室【dp】
  13. can not create symbolic link HDFS解压自动配置lib报错。
  14. iOS: 控制UIView的外形
  15. listView优化方案
  16. iOS多线程编程之线程间的通信(转载)
  17. C++创建自己的库文件(dll文件创建和编译)
  18. STM32L476的RTC使用问题记录
  19. Oracle cmd乱码
  20. esper(4-3)-Non-Overlapping Context

热门文章

  1. Altium Designer 18 画keepout层与将keepout层转换成Mechanical1层的方法
  2. [从今天开始修炼数据结构]串、KMP模式匹配算法
  3. react可拖动的好用的树结构插件
  4. linux任务计划cron、chkconfig工具、systemd管理服务、unit和target介绍
  5. C语言l博客作业05
  6. 2019-2020-1 20199304《Linux内核原理与分析》第五周作业
  7. SwiftyUserDefaults-封装系统本地化的框架推荐
  8. 关于软件定义IT基础设施的未来,深信服是这么思考的
  9. OCR文字识别在计算机视觉的重要性、基本技术和最新进展
  10. 【跟唐老师学习云网络】-第8篇 iptables - filter过滤功能