runtime
1、runtime是一套由C语言Api组成的runtime的库。
2、runtime会尽量把代码的执行决策推迟到运行时。
3、OC是动态语言,最后代码都会转换成runtime代码。
runtime的使用场景
1、动态的创建和获取类
2、动态为一个类添加属性和方法
3、在程序运行时遍历类中的成员变量,属性或方法
4、可以调换两个方法的逻辑实现
使用时一定要注意一定要引入<objc/runtime.h>
这里还需要注意的一点是:需要把 图中的这一选项设置为NO
#import "LTRunTimeViewController.h"
#import <objc/runtime.h>
#import <objc/message.h>
#import "LTRunTime.h"
@interface LTRunTimeViewController ()
@end
@implementation LTRunTimeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self traversalInstanceVariables];
[self traversalAttributes];
[self traversalTargetMethod];
}
#pragma mark 动态创建类
- (void)createClass
{
//创建一个类,继承NSObject
Class MyClass = objc_allocateClassPair([NSObject class], "myclass", 0);
//添加一个NSString的变量,第四个参数是对其方式,第五个参数是参数类型
if (class_addIvar(MyClass, "itest", sizeof(NSString *), 0, "@")) {
NSLog(@"add ivar success");
}
//添加属性 一个属性相关项的配置
objc_property_attribute_t type = { "T", "@\"NSString\"" };//T 是type
objc_property_attribute_t ownership = { "C", "" }; // C = copy
objc_property_attribute_t backingivar = { "V", "_privateName" };//variable name
objc_property_attribute_t attrs[] = { type, ownership, backingivar };
class_addProperty(MyClass, "privateName", attrs, 3);
//myclasstest是已经实现的函数,"v@:"这种写法见参数类型连接
class_addMethod(MyClass, @selector(myclasstest:), (IMP)myclasstest, "v@:@");
class_addMethod(MyClass, @selector(name), (IMP)nameGetter, "@@:");
//注册这个类到runtime系统中就可以使用他了
objc_registerClassPair(MyClass);
//生成了一个实例化对象
id myobj = [[MyClass alloc] init];
NSString *str = @"asdb";
//给刚刚添加的变量赋值
// object_setInstanceVariable(myobj, "itest", (void *)&str);在ARC下不允许使用
[myobj setValue:str forKey:@"itest"];
//调用myclasstest方法,也就是给myobj这个接受者发送myclasstest这个消息
[myobj myclasstest:10];
}
NSString *nameGetter(id self, SEL _cmd) {
Ivar ivar = class_getInstanceVariable([self class], "_privateName");
return object_getIvar(self, ivar);
}
//这个方法实际上没有被调用,但是必须实现否则不会调用下面的方法
- (void)myclasstest:(int)a
{
}
//调用的是这个方法
static void myclasstest(id self, SEL _cmd, int a) //self和_cmd是必须的,在之后可以随意添加其他参数
{
Ivar v = class_getInstanceVariable([self class], "itest");
//返回名为itest的ivar的变量的值
id o = object_getIvar(self, v);
//成功打印出结果
NSLog(@"%@", o);
NSLog(@"int a is %d", a);
}
#pragma mark 遍历实例变量
-(void)traversalInstanceVariables{
LTRunTime *person = [[LTRunTime alloc]init];
NSLog(@"所属的类%@",[person class]);
Class personClass = person.class;
unsigned int outCount;
//遍历实例变量
Ivar *ivarPtr = class_copyIvarList(personClass, &outCount);
for (NSInteger i = 0; i< outCount ; i++) {
Ivar ivar = ivarPtr[i];
NSLog(@"ivar 实例变量: %s",ivar_getName(ivar));
}
}
#pragma 遍历属性
-(void)traversalAttributes {
LTRunTime *person = [[LTRunTime alloc]init];
NSLog(@"所属的类%@",[person class]);
Class personClass = person.class;
unsigned int outCount;
objc_property_t *propertyPtr = class_copyPropertyList(personClass, &outCount);
for (NSInteger i = 0; i < outCount ; i++) {
objc_property_t t = propertyPtr[i];
NSLog(@"属性的名称 %s",property_getName(t));
}
}
#pragma mark 遍历对象方法
-(void)traversalTargetMethod {
LTRunTime *person = [[LTRunTime alloc]init];
NSLog(@"所属的类%@",[person class]);
Class personClass = person.class;
unsigned int outCount;
Method *methods = class_copyMethodList(personClass, &outCount);
for (NSInteger i = 0; i < outCount; i++) {
Method method =methods[i];
SEL selector = method_getName(method);
NSLog(@"%@",NSStringFromSelector(selector));
}
[person setHeight:@"10"];
objc_msgSend(person,@selector(dowork));
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}