创建类
因为要使用runtime的api,所以要导入头文件#import <objc/runtime.h>
创建类代码:
//创建
Class Car = objc_allocateClassPair([NSObject class], "Car", 0);
//注册
objc_registerClassPair(Car);
调用了runtime的两个api方法
-
objc_allocateClassPair:创建类
- 参数1:父类,和我们手动创建类一样,需要指定父类
- 参数2:类的名字
-
参数3:通常传0,可以在注释中查看。
-
objc_registerClassPair:注册到内存
- 参数:创建的类。
添加成员变量
添加成员变量ivar
//创建
Class Car = objc_allocateClassPair([NSObject class], "Car", 0);
//添加成员变量
class_addIvar(Car, "name", sizeof(NSString *), log2(sizeof(NSString *)), "@");
//注册
objc_registerClassPair(Car);
需要注意:class_addIvar在objc_allocateClassPair和objc_registerClassPair两个api调用之间添加。因为类在编译期需要确认空间大小,成员变量是需要被计算到初始大小中。所以需要在加载内存之前就得加入到类中。
成员变量其实存储在类结构体中ro中,ro就是read only,只读的状态。为什么要有‘只读’的这一部分呢?我们都知道OC是动态语言,可以对类增加方法、属性等操作。但是原始类中的方法和属性等信息,首先需要保存到一个只读的区域内,然后在复制到rw(可读写的)区域内。这样的好处是:当动态增加新的方法和属性的时候,直接操作rw区域就可以了。在查找方法的时候,也只在rw读取就可以了。而且ro区域中的内容给不会变动,保证不会被数据‘污染’。ro和rw的关系,可以参考下图:红色标记出来的就是rw和ro

添加属性
添加属性需要注意一些内容:
- 类的属性是有属性的,例如:
@property (copy, nonatomic) NSString *subName;
中括号的部分就是类属性的属性。这部分也需要调用api添加。 - 要实现set和get方法。
把相关api的调用封装成一个方法:
void test_class_addProperty(Class targetClass , const char *propertyName){
// 添加属性
objc_property_attribute_t type = { "T", [[NSString stringWithFormat:@"@\"%@\"",NSStringFromClass([NSString class])] UTF8String] }; //type
objc_property_attribute_t ownership1 = { "C", "" }; // C = copy
objc_property_attribute_t ownership2 = { "N", "" }; //N = nonatomic
objc_property_attribute_t ivar = { "V", [NSString stringWithFormat:@"_%@",[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]].UTF8String }; //variable name
objc_property_attribute_t attrs[] = {type, ownership1, ownership2, ivar};
class_addProperty(targetClass, propertyName, attrs, 4);
// 添加setter + getter 方法
class_addMethod(targetClass, @selector(setInfo:), (IMP)testSetter, "v@:@");
class_addMethod(targetClass, @selector(info), (IMP)testInfo, "@@:");
}
添加属性的时候ownership的两个变量中分别设置了‘C’和‘N’,分别代表的是‘copy’和‘nonatomic’,其他的配置如图:

添加方法的时候,例如添加setter方法class_addMethod(targetClass, @selector(setInfo:), (IMP)testSetter, "v@:@");
- 参数1:目标类
- 参数2:sel
- 参数3:imp
-
参数4:方法签名,v代表返回值为void类型,@代表对象,冒号(:)是sel。更多参数参考下图:
demo地址:动态添加类Demo
网友评论