runtime的一些理解与用法
来源:互联网 发布:华藏净宗网络直播台 编辑:程序博客网 时间:2024/05/22 05:04
Runtime概述:
runtime是一套由C语言API组合成的Runtime库;并尽可能把代码的执行决策推迟到运行时。OC是一门动态语言,OC代码最终都会转换成底层Runtime的代码。
- Runtime的使用场景:
1.动态获取、创建类;
// 动态创建类 Class pCreateClass = objc_allocateClassPair([NSObject class], "pClass", 0);
// 动态获取类 NSLog(@"pCreateClass's meta class is %p",object_getClass([pCreateClass class]));
2.动态为一个类增加属性或方法;首先要明确 Objective-C 作为一种动态语言,它会将部分代码放置在运行时的过程中执行,而不是编译时,所以在执行代码时,不仅仅需要的是编译器,也同时需要一个运行时环境(Runtime),为了满足一些需求,苹果开源了 Runtime Source 并提供了开放的 api 供开发者使用。其次,class_addMethod运用场景。当项目中,需要继承某一个类(subclass),但是父类中并没有提供我需要的调用方法,而又不清楚父类中某些方法的具体实现;或者,需要为这个类写一个分类(category),在这个分类中,可能需要替换/新增某个方法(注意:不推荐在分类中重写方法,而且也无法通过 super 来获取所谓父类的方法)。大致在这两种情况下,我们可以通过 class_addMethod 来实现我们想要的效果。在 Objective-C 中,正常的调用方法是通过消息机制(message)来实现的,那么如果类中没有找到发送的消息方法,系统就会进入找不到该方法的处理流程中,如果在这个流程中,我们加入我们所需要的新方法,就能实现运行过程中的动态添加了。这个流程或者说机制,就是 Objective-C 的 Message Forwarding 2.1增加属性
objc_registerClassPair(pCreateClass); id myobj = [[pCreateClass alloc] init]; NSLog(@"---->%@",[myobj class]); //生成了一个实例化对象// id myobj = [[pCreateClass alloc] init]; NSString *str = @"testString"; //给刚刚添加的变量赋值 // object_setInstanceVariable(myobj, "m_strTest", (void *)&str);在ARC下不允许使用 [myobj setValue:str forKey:@"m_strTest"];
2.2增加方法
// Class cls:cls 参数表示需要添加新方法的类。// SEL name:name 参数表示 selector 的方法名称,可以根据喜好自己进行命名。// IMP imp:imp 即 implementation ,表示由编译器生成的、指向实现方法的指针。也就是说,这个指针指向的方法就是我们要添加的方法。// const char *types:最后一个参数 *types 表示我们要添加的方法的返回值和参数。 class_addMethod(pCreateClass, @selector(pClassMethod:), (IMP)pClassMethod1, "v@:"); [myobj pClassMethod:10];
//C 语言风格写新函数//self 代表着函数本身;而 _cmd 则是一个 SEL 数据体;包含了具体的方法地址,在之后可以随意添加其他参数static void pClassMethod1(id self, SEL _cmd, int sender){ Ivar v = class_getInstanceVariable([self class], "m_strTest"); //返回名为m_strTest的ivar的变量的值 id strTest = object_getIvar(self, v); NSLog(@"%@", strTest); NSLog(@"int sender is %d", sender);}//OC 语言风格写新函数- (void)pClassMethod1:(int)sender { Ivar v = class_getInstanceVariable([self class], "m_strTest"); //返回名为m_strTest的ivar的变量的值 id strTest = object_getIvar(self, v); NSLog(@"%@", strTest); NSLog(@"int sender is %d", sender);}- (void)pClassMethod:(int)sender{ NSLog(@"pClassMethod");}
3.在程序运行时遍历类中的实例变量、属性或方法
RunTimeData* pData = [[RunTimeData alloc] init]; NSLog(@"%@",[pData class]); //遍历实例变量 Class objectClass = pData.class; unsigned int nOutCount = 0; Ivar* ivarPtr = class_copyIvarList(objectClass, &nOutCount); for (NSInteger i = 0; i < nOutCount; i++) { Ivar ivar = ivarPtr[i]; NSLog(@"实例变量:%s",ivar_getName(ivar)); }
//遍历属性 objc_property_t* propPtr = class_copyPropertyList(objectClass, &nOutCount); for (NSInteger i = 0; i < nOutCount; i++) { objc_property_t pPtr = propPtr[i]; NSLog(@"属性:%s",property_getName(pPtr)); }
//遍历对象方法(.cxx_destruct这个是类中隐藏的函数,不需要去理会) Method* methodClass = class_copyMethodList(objectClass, &nOutCount); for (NSInteger i = 0; i < nOutCount; i++) { Method method = methodClass[i]; SEL selector = method_getName(method); NSLog(@"方法:%@",NSStringFromSelector(selector)); }
4.调换两个方法的逻辑实现(Method Swizzle) 4.1在iOS中实现AOP(Aspect Oriented Programming(面向切面编程))编程思想的一种方式是Method Swizzling。Method Swizzling利用Runtime特性把一个方法的实现和另一个方法的实现进行替换,在程序运行时修改Dispatch Table里SEL和IMP的映射关系。通过 swizzling method 改变目标函数的 selector 所指向的实现,然后在新的实现中实现附加的操作,完成之后再调用原来的处理逻辑。 4.2Method Swizzling的优势 继承:修改多,无法保证他人一定继承基类 类别:类别中重写方法会覆盖原来的实现,大多时候,重写一个方法是为了添加一些代码,而不是完全取代它。如果两个类别都实现了相同的方法,只有一个类别的方法会被调用到。 AOP优势:减少切面业务的重复编码,减少与其他业务的耦合,把琐碎事务从主业务中分离。
实例:
RunTimeData.m
#import "RunTimeData.h"#import <objc/runtime.h>+ (void)load{//在这里调用时因为+(void)load方法在main()前类载入内存时会调用一次。 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [RunTimeData swizzeleViewDidLoad]; });} + (void)swizzeleViewDidLoad{ Class pVC = NSClassFromString(@"ViewController"); Method orgiMethod = class_getInstanceMethod(pVC, @selector(viewDidLoad)); Method newMethod = class_getInstanceMethod([self class], @selector(swizzeleViewDidLoad)); BOOL isAddMethod = class_addMethod(pVC, @selector(swizzeleViewDidLoad), method_getImplementation(newMethod), method_getTypeEncoding(newMethod)); if (isAddMethod) { Method newMethodInVC = class_getInstanceMethod(pVC, @selector(swizzeleViewDidLoad)); method_exchangeImplementations(orgiMethod, newMethodInVC); }}//两行代码书写顺序1(注释顺序2)- (void)swizzeleViewDidLoad{ [self swizzeleViewDidLoad];//正常情况下在类中调用,必然进入无限循环。然而,在Method Swizzling中,这样才是正确的用法。理解下其中的逻辑。在load方法中实现了Swizzling,系统SEL的viewDidLoad指向的是swizzeleViewDidLoad的实现,方法SEL名为swizzeleViewDidLoad指向的是系统名为viewDidLoad的实现。所以在调用过程中相当两个方法交叉调用了,并没有导致死循环。 NSLog(@"class --> %@ _cmd==%@",[self class],NSStringFromSelector(_cmd));}//两行代码书写顺序2(注释顺序1)- (void)swizzeleViewDidLoad{ NSLog(@"class --> %@ _cmd==%@",[self class],NSStringFromSelector(_cmd)); [self swizzeleViewDidLoad];}
ViewController.m
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"pVC ViewDidLoad"); }
两行代码书写顺序1日志打印结果
两行代码书写顺序2日志打印结果
这里输出的结果反映出一些问题,具体问题描述可以查看下面的 [Method Swizzle 的一些注意事项]
Method Swizzle
Method Swizzle 的一些注意事项
Objective-C Runtime 1小时入门教程
1 0
- runtime的一些理解与用法
- RunTime的一些用法
- Runtime 的一些用法
- ios的runtime的一些小用法
- 对Objective-C的runtime的一些理解
- 对runtime和runloop的一些个人理解
- runtime的个人理解
- 关于runtime的理解
- 对runtime的理解
- Runtime的理解
- iOS runtime的理解
- runtime的简单理解
- runtime的理解
- 理解OC的Runtime
- runtime的理解
- iOS runtime的理解
- Ios runtime的理解
- 对Runtime的理解
- 欢迎使用CSDN-markdown编辑器
- OkHttp
- requestAnimationFrame
- android sepolicy报错解决
- solr 查询条件过多异常处理
- runtime的一些理解与用法
- [Spring MVC] 入门基础
- 欢迎使用CSDN-markdown编辑器
- bootstrap学习总结-js组件(四)
- LightOJ1236
- 最小周期串
- nginx提示502 错误
- Keepalived + Nginx实现高可用 Web负载均衡
- java字符串排序