关于runtime的使用心得
来源:互联网 发布:mac口红的质地 编辑:程序博客网 时间:2024/05/06 08:45
最近一直在听朋友用runtime进行装逼,就去学习了一下,顺便整理出来方便以后查看。
1.什么是Runtime?
runtime是底层C语言的API,从表面理解就是动态运行时。它会在程序运行时把OC转换成C,比如:[self name]会装换成objc_msgSend(self,@selector(name)).
2.runtime的相关定义以及方法
/// An opaque type that represents a method in a class definition.
typedefstruct objc_method *Method;
/// An opaque type that represents an instance variable.
typedefstruct objc_ivar *Ivar;
/// An opaque type that represents a category.
typedefstruct objc_category *Category;
/// An opaque type that represents an Objective-C declared property.
typedefstruct objc_property *objc_property_t;
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE;
const char *name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;
struct objc_method_list **methodLists OBJC2_UNAVAILABLE;
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
3.runtime的实际应用
(1)获取类中相关属性
1.首先建立一个类,如下:
#import <Foundation/Foundation.h>
@interface Student : NSObject <NSCoding,NSCopying>
{
int _age;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *number;
@property (nonatomic, copy) NSString *sex;
- (void)setAge:(int)age;
- (int)age;
2.在主控制器里调用,记得导入#import <objc/runtime.h>
unsigned int outCount =0;
//获取成员变量列表
Ivar *ivarList = class_copyIvarList([Student class], &outCount);
for (int i =0; i < outCount; i ++) {
Ivar ivar = ivarList[i];
const char *ivarName = ivar_getName(ivar);
NSLog(@"ivar = %@",[NSString stringWithUTF8String:ivarName]);
}
//获取属性列表
objc_property_t *propertyList = class_copyPropertyList([Student class], &outCount);
for (int i =0; i < outCount; i ++) {
const char *propertyName = property_getName(propertyList[i]);
NSLog(@"property = %s",propertyName);
}
//获取方法列表
Method *methodList = class_copyMethodList([Student class], &outCount);
for (int i =0; i < outCount; i ++) {
Method method = methodList[i];
NSLog(@"method = %@",NSStringFromSelector(method_getName(method)));
}
//获取协议列表
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([Student class], &outCount);
for (int i =0; i < outCount; i ++) {
Protocol *protocol = protocolList[i];
const char *protocolName = protocol_getName(protocol);
NSLog(@"protocol = %s",protocolName);
}
3.打印结果如下:
4.应用场景
可以利用遍历类的属性进行快速的归档
在没用runtime之前,归档是这样的:
对于属性少的还好说,如果有几十上百个,那就要写上百个[aCoderencodeObject:self.nameforKey:@"name"];那样就会非常麻烦,然而利用runtime就非常方便了,如图:
(2)交换方法
应用场景:比如想要获取当前控制器,就可以用自己的方法来交换系统的方法,要先建立一个UIViewController的分类,代码如下:
该代码是在网上复制粘贴的。
#import "UIViewController+swizzling.h"#import @implementation UIViewController (swizzling)//load方法会在类第一次加载的时候被调用//调用的时间比较靠前,适合在这个方法里做方法交换+ (void)load{ //方法交换应该被保证,在程序中只会执行一次 static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //获得viewController的生命周期方法的selector SEL systemSel = @selector(viewWillAppear:); //自己实现的将要被交换的方法的selector SEL swizzSel = @selector(swiz_viewWillAppear:); //两个方法的Method Method systemMethod = class_getInstanceMethod([self class], systemSel); Method swizzMethod = class_getInstanceMethod([self class], swizzSel); //首先动态添加方法,实现是被交换的方法,返回值表示添加成功还是失败 BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod)); if (isAdd) { //如果成功,说明类中不存在这个方法的实现 //将被交换方法的实现替换到这个并不存在的实现 class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod)); }else{ //否则,交换两个方法的实现 method_exchangeImplementations(systemMethod, swizzMethod); } });}- (void)swiz_viewWillAppear:(BOOL)animated{ //这时候调用自己,看起来像是死循环 //但是其实自己的实现已经被替换了 [self swiz_viewWillAppear:animated]; NSLog(@"swizzle");}@end
在一个自己定义的viewController中重写viewWillAppear- (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; NSLog(@"viewWillAppear");}
(3)拦截调用
//当你调用一个不存在的类方法的时候,会调用这个方法,默认返回NO,你可以加上自己的处理然后返回YES。
+ (BOOL)resolveClassMethod:(SEL)sel;
//和第一个方法相似,只不过处理的是实例方法。
+ (BOOL)resolveInstanceMethod:(SEL)sel;
//将你调用的不存在的方法重定向到一个其他声明了这个方法的类,只需要你返回一个有这个方法的target。
- (id)forwardingTargetForSelector:(SEL)aSelector;
//将你调用的不存在的方法打包成NSInvocation传给你。做完你自己的处理后,调用invokeWithTarget:方法让某个target触发这个方法。
- (void)forwardInvocation:(NSInvocation *)anInvocation;
(4)动态添加方法
class_addMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)
其中class_addMethod的四个参数分别是:
1.Class cls给哪个类添加方法,比如self
2.SEL name添加的方法,是重写的拦截调用传进来的selector。
3.IMP imp方法的实现,C方法的方法实现可以直接获得。如果是OC方法,可以用+ (IMP)instanceMethodForSelector:(SEL)aSelector;获得方法的实现。
4.代表有无参数的方法。
首先从外部调用一个不存在的方法
//调用不存在的方法[student performSelector:@selector(resolveAdd:) withObject:@"test"];然后再student对象内部重写拦截方法
void runAddMethod(id self, SEL _cmd, NSString *string){ NSLog(@"add C IMP ", string);}+ (BOOL)resolveInstanceMethod:(SEL)sel{ //给本类动态添加一个方法 if ([NSStringFromSelector(sel) isEqualToString:@"resolveAdd:"]) { class_addMethod(self, sel, (IMP)runAddMethod, "v@:*"); } return YES;}
(5)关联对象
关联对象可以给一个类添加新的属性。
总结:runtime在实际开发中用到的很少,用的较多就是交换方法,但是一定要保证只交换一次,否则会弄的很乱,其次用的多的是遍历类的属性进行归档,不过现在都有很多第
三方库,也很少用到了。不过了解一下其机制还是不错的。
- 关于runtime的使用心得
- 使用Runtime.exec()心得
- java关于Runtime的使用
- 关于emule的使用心得
- 关于虚拟机的使用心得
- 关于iebook的使用心得
- 关于DEVExpressSkins的使用心得
- 关于javamail的使用心得
- 关于ueditor的使用心得
- 关于使用sublime的心得
- 关于ThreadLocal的使用心得
- 关于Dagger2的使用心得
- 关于RxJava2的使用心得
- 关于iview的使用心得
- runtime的理解和心得
- runtime心得
- 关于runtime的理解
- 关于嵌套使用DataList的心得[原创]
- 什么上下文
- Unity3D之高级渲染-Shader Forge增强版
- VS2013下安装配置Qt组件环境
- win8安装RobotFramework
- 【剑指offer】最小的k个数
- 关于runtime的使用心得
- C语言正则表达式详解 regcomp() regexec() regfree()详解
- 字符串补0或空格
- 自定义弹出模态框
- 什么是 MIME TYPE?
- Linux系统文件架构
- 分数四则运算
- git ssh 设置
- 王小二切饼