iOS笔记 – Runtime 01:isa为什么优化成了共用体


Runtime

1 – OC的动态性是由 Runtime API来支撑的, Runtime API提供的接口基本上是 C语言的,源码是由 C、C++、汇编所编写的

2 – 要想学习 Runtime,首先要先了解它的一些底层数据结构,比如 isa指针、union

union

1 – arm64架构之前,isa就是一普通指针,存储了 Class、Meta-Class对象的内存地址;而 arm64之后就把 isa优成了共同体结构,使用位域来存储更多的信息

2 – 为什么使用共用体优化 isa

① 未使用共用体之前

 1 #import <Foundation/Foundation.h>
 2 #import <objc/runtime.h>
 3 @interface Person : NSObject
 4 
 5 // Person中有三个属性:高富帅
 6 @property (assign, nonatomic, getter = isTall) BOOL tall;
 7 @property (assign, nonatomic, getter = isRich) BOOL rich;
 8 @property (assign, nonatomic, getter = isHansome) BOOL handsome;
 9 
10 @end
11 
12 @implementation Person
13 
14 @end
15 
16 int main(int argc, const char * argv[]) {
17     @autoreleasepool {
18 
19         Person *person = [[Person alloc] init];
20         person.rich = YES;
21         person.tall = NO;
22         person.handsome = NO;
23         
24         NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHansome);
25         
26         // 内存大小
27         NSLog(@"%zd", class_getInstanceSize([Person class]));// 16
28         // 3个 BOOL属性共占 3字节;内部的 isa占 8字节;总计 11字节
29         // 内存对其,输出 16
30         
31     }
32     return 0;
33 }

② 使用共用体:一个字节就可以对 Person的高、富、帅 3个信息进行存储

  1 #import <Foundation/Foundation.h>
  2 #import <objc/runtime.h>
  3 
  4 // 掩码一般同按位与 &搭配使用
  5 // 注意细节:建议掩码使用小括号括起来,方便运算、阅读
  6 #define TallMask (1<<0)       // 0b 0000 0001
  7 #define RichMask (1<<1)       // 0b 0000 0010
  8 #define HandsomeMask (1<<2)   // 0b 0000 0100
  9 
 10 @interface Person : NSObject{
 11     
 12     // 使用一个字节就可以包含高、富、帅三者的信息
 13     char _TRH;// tallRichHansome
 14 }
 15 
 16 // 高富帅
 17 @property (assign, nonatomic, getter = isTall) BOOL tall;
 18 @property (assign, nonatomic, getter = isRich) BOOL rich;
 19 @property (assign, nonatomic, getter = isHansome) BOOL handsome;
 20 
 21 @end
 22 
 23 @implementation Person
 24 
 25 // 初始值我们约定:tall = YES; rich = YES;  handsome = NO;
 26 - (instancetype)init{
 27     
 28     if (self = [super init]) {
 29         
 30         _TRH = 0b00000011; // 高、富、不帅
 31     }
 32     return self;
 33 }
 34 
 35 // 赋值比较绕,我们先把取值搞定
 36 // getter:利用位与运算可取出对应位的值即可
 37 - (BOOL)isTall{
 38     
 39     // 使用两个 !完成 强制 BOOL转换的功能
 40     
 41     return !!(_TRH & TallMask);// 同 return (BOOL)(_TRH & TallMask);
 42 }
 43 
 44 - (BOOL)isRich{
 45     
 46     return !!(_TRH & RichMask);
 47 }
 48 
 49 - (BOOL)isHansome{
 50     return (BOOL)(_TRH & HandsomeMask);
 51 }
 52 
 53 
 54 // setter
 55 - (void)setTall:(BOOL)tall{
 56     
 57      
 58     if (tall) {
 59         _TRH |= TallMask;// 如果是 YES,使用位或
 60     } else {
 61         
 62         // 如果是 NO:先按位取反然后后再进行位与运算
 63         _TRH &= ~TallMask;
 64         
 65         // ~0001 == 1110
 66         // 1110 & 0011 == 0010
 67     }
 68 }
 69 
 70 - (void)setRich:(BOOL)rich{
 71     if (rich) {
 72         _TRH |= RichMask;
 73     } else {
 74         _TRH &= ~RichMask;
 75     }
 76 }
 77 
 78 - (void)setHandsome:(BOOL)handsome{
 79     
 80     if (handsome) {
 81         
 82         _TRH |= HandsomeMask;
 83         // 0011 | 0100 == 0111
 84         
 85         NSLog(@"%d",HandsomeMask);
 86     } else {
 87         _TRH &= ~HandsomeMask;
 88     }
 89 }
 90 
 91 @end
 92 
 93 int main(int argc, const char * argv[]) {
 94     @autoreleasepool {
 95         
 96         Person *person = [[Person alloc] init];
 97         NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHansome);
 98         // tall:1 rich:1 hansome:0
 99         
100         //赋值后
101         person.tall = NO;
102         person.rich = NO;
103         person.handsome = NO;
104         NSLog(@"tall:%d rich:%d hansome:%d", person.isTall, person.isRich, person.isHansome);
105         // tall:0 rich:0 hansome:0
106     }
107     return 0;
108 }

 

原创文章,作者:carmelaweatherly,如若转载,请注明出处:https://blog.ytso.com/271598.html

(0)
上一篇 2022年7月5日
下一篇 2022年7月5日

相关推荐

发表回复

登录后才能评论