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 }