iOS之Runtime - 常用的API

发布时间 2023-03-22 21:09:23作者: 带缝儿的沙盒

Runtime 常用的 API

1 - 类

② 成员变量

③ 属性

④ 方法

⑤ 其他

2 - 如何使用

① 新建 Person 和 Animal 两个类,如下

② 代码示例

  1 #import <Foundation/Foundation.h>
  2 #import "Person.h"
  3 #import "Animal.h"
  4 #import <objc/runtime.h>
  5 
  6 void run(id self, SEL _cmd){
  7     
  8     NSLog(@"___%@ - %@", self, NSStringFromSelector(_cmd));
  9 }
 10 
 11 // 成员变量
 12 int main(int argc, const char * argv[]) {
 13     
 14     // 获取成员变量信息
 15     Ivar ageIvar = class_getInstanceVariable([Person class], "_age");
 16     
 17     // 注意返回的时 C语言 字符串
 18     NSLog(@"%s %s", ivar_getName(ageIvar), ivar_getTypeEncoding(ageIvar)); // _age  i
 19     
 20     // 设置和获取成员变量的值
 21     Ivar nameIvar = class_getInstanceVariable([Person class], "_name");
 22     
 23     // 给成员变量赋值
 24     Person *person = [[Person alloc] init];
 25     object_setIvar(person, nameIvar, @"abc");
 26     object_setIvar(person, ageIvar, (__bridge id)(void *)100); // 整型不能直接赋值
 27     NSLog(@"%@ %d", person.name, person.age);//  abc 100
 28     
 29     // 成员变量的数量
 30     unsigned int count;
 31     // 第二个参数需要传进一个整型地址,其函数内部返回一个值用来记录成员变量数量
 32     Ivar *ivars = class_copyIvarList([Person class], &count);
 33     
 34     NSLog(@"%d",count); // 2
 35     
 36     // 遍历成员变量
 37     for (int i = 0; i < count; i++) {
 38         Ivar ivar = ivars[i];
 39         NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
 40         // i = 0 时   _age i
 41         // i = 1 时   _name @"NSString"
 42     }
 43     
 44     // 需要释放
 45     free(ivars);
 46     
 47     return 0;
 48 }
 49 
 50 
 51 
 52 //
 53 void testONE(){
 54     
 55     Person *pe1 = [Person new];
 56     Animal *an1 = [Animal new];
 57     
 58     // 设置 isa 指向的 Class
 59     object_setClass(pe1, [Animal class]);
 60     
 61     // 获取 isa 指向的 Class
 62     NSLog(@"%@",object_getClass(pe1)); // Animal 类对象
 63     [pe1 runAway]; //  <Animal: 0x10040d690> runAway !
 64     
 65     NSLog(@"%@",object_getClass([Person class]));// Person 元类
 66     NSLog(@"%@",object_getClass(object_getClass([Person class]))); // 根类  NSObject
 67     
 68     // 判断是不是一个 Class
 69     NSLog(@"%d   %d   %d",object_isClass(an1),object_isClass([Animal class]),object_isClass(object_getClass([Person class])));
 70     // 0   1   1
 71     
 72 }
 73 
 74 // 方法
 75 void testTWO(){
 76     
 77     // 创建一个新的类
 78     Class NewClass = objc_allocateClassPair([NSObject class], "God", 0);
 79     
 80     // 添加成员变量(Class, 成员变量, 内存大小, 内存对齐, 数据类型的encode编码)
 81     // 注意:添加成员变量必须在类注册之前完成
 82     class_addIvar(NewClass, "_age", 4, 1, @encode(int));
 83     class_addIvar(NewClass, "_weight", 4, 1, "i"); // i 就是 int 的 encode编码
 84     
 85     // 新类创建后需要注册
 86     objc_registerClassPair(NewClass);
 87     
 88     // 添加方法:可以在类注册之后完成
 89     class_addMethod(NewClass, @selector(run), (IMP)run, "v@:");
 90     
 91     id erlang = [NewClass new];
 92     
 93     [erlang setValue:@10 forKey:@"_age"];
 94     [erlang setValue:@20 forKey:@"_weight"];
 95     [erlang run];
 96     
 97     // 将 erlang 销毁
 98     erlang = nil;
 99     
100     NSLog(@"%@ %@", [erlang valueForKey:@"_age"], [erlang valueForKey:@"_weight"]);
101     
102     // 在不需要这个类时释放:如果前面 erlang 没有置空(销毁),执行此行代码则程序 Crash
103     objc_disposeClassPair(NewClass);// 执行此函数前,它不允许前面还有该类的实例,否则 crash
104     
105 }