众所周知,Objective-C是iOS开发的第一语言(虽然最近两年Swift发展迅猛,在最近的TIOBE编程语言排行榜上Swift的排名已经超过了Objective-C,但是现在iOS主流应用依然还是用Objective-C完成的)。Objective-C有一个可以称之为杀手级的语言特征—-动态性,而OC的动态性最主要依赖的就是运行时系统(RunTime)。
很多人在刚接触OC的运行时系统(RunTime)时,觉得它很深奥,因为它用到了C语言的API,毕竟很多的iOS程序员的C语言水平并不是很强,甚至到了看到C语言就恐惧的地步。因此在这里我通过几个简单的案例来阐述RunTime机制的强大之处,算是一个小小的入门了。
1-最简单的运行时系统应用:根据字符串来调用内存中的一个类。
这是运行时机制最常见也是最简单的应用了,它简单到甚至不用在项目中写入#import
<objc/runtime.h>用来导入runtime库。它根据传入的字符串来获取内存中存在的类。
其代码如下:
//1-根据字符串返回一个类
Class cls =NSClassFromString(@”Person”);
//2-根据类来创建对象
id person = [[cls alloc]init];
//3-给person的属性赋值
[person performSelector:@selector(setName:)withObject:@”wang”];
//4-返回person的name属性值(使用KVC返回属性值)
NSLog(@”person的name是%@”,[person valueForKey:@”name”]);
//5-调用person的eat方法
if([person respondsToSelector:@selector(Eat)])
{
[person performSelector:@selector(Eat)withObject:nil];
}
else
{
NSLog(@”person不存在的方法”);
}
2- 在程序运行时动态地添加一个类
当需要在程序运行时动态地添加一个新的类到内存中时,我们需要用到C语言的API,需要导入runtime库,此时动态生成的类就会存在于内存中。
代码如下:
#import <objc/runtime.h>
//1-设置类名(类名是常量)
const char*className =”Dog”;
//2-根据类名获取类
Class cls =objc_getClass(className);
//3-判断类存不存在
if(!cls)
{
//4-如果类不存在于当前的内存下,则需要重新根据类名来创建这个类
//4-1设置运行时类的父类
Class superClass = [NSObject class];
//4-2在运行时下创建类
cls =objc_allocateClassPair(superClass, className, 0);
//5-判断类存不存在
if(!cls)
{
NSLog(@”Dog类不存在”);
return;
}
else
{
//此时动态创建的Dog类存在于内存中
NSLog(@”Dog类存在”);
}
//6-在内存中注册类!!!!
#warning在内存中注册类,一定要加!!!!!
objc_registerClassPair(cls);
}
else
{
//类存在说明在当前的内存中已经存在了这个类(包括一些UIKit的系统类等)
NSLog(@”类已经存在”);
}
通过代码可以看出来,一股浓浓的C语言代码风格袭来,在内存中根据类名获取类还有在运行时创建一个新的类都用到了C语言的函数。
3- 运行时给内存中的类添加新的方法
此时也需要添加C语言的API,需要导入runtime库,代码如下:
-(void)RunTime3withClassName:(NSString*) className
{
//1-获取内存中相关的类
Class cls =NSClassFromString(className);
if(!cls)
{
NSLog(@”%@类不存在”,className);
return;
}
else
{
NSLog(@”%@类存在”,className);
}
//2-添加方法的实现(使用block实现,在block内传入方法参数)
IMP myImp =imp_implementationWithBlock(^(id_self,NSString*str){
NSLog(@”Hello %@”,str);
});
class_addMethod(cls,@selector(sayHello:), myImp,”v@:@”);
//3-判断有没有添加方法成功
id person = [[cls alloc]init];
if([person respondsToSelector:@selector(sayHello:)])
{
[person performSelector:@selector(sayHello:)withObject:@”World”];
}
else
{
NSLog(@”当前的方法不存在”);
}
}