iOS runtime详解一
RunTime是什么?
众所周知OC是一门高级编程语言,也是一门动态语言。有动态语言那也就有静态语言,静态语言---编译阶段就要决定调用哪个函数,如果函数未实现就会编译报错。如C语言。动态语言---编译阶段并不能决定真正调用哪个函数,只要函数声明过即使没有实现也不会报错。如OC语言。
高级编程语言想要成为可执行文件需要先编译为汇编语言再汇编为机器语言,机器语言也是计算机能够识别的唯一语言,但是OC并不能直接编译为汇编语言,而是要先转写为纯C语言再进行编译和汇编的操作,从OC到C语言的过渡就是由runtime来实现的。然而我们使用OC进行面向对象开发,而C语言更多的是面向过程开发,这就需要将面向对象的类转变为面向过程的结构体。
RunTime的使用场景?
场景1-交换方法
在真正做项目的时候,有时候会接受不同的项目,但是对于你接受的项目,有自己新搭建的项目,也有经过很多人手的项目,参差不齐,对于有些需求,修改涉及到以前的代码,如果一点点的修改,费时费力而且见效很慢,这时候就可以使用Runtime的交换方法来统一处理,我在做项目的时候就遇到过这种需求,需要将项目中所有有负值的地方全部处理成红色,我采用的就是和系统的setText:方法交换,仅仅就换了几分钟就将这个需求搞定。
#import <UIKit/UIKit.h>
@interface UILabel (TextStyle)
@end
#import "UILabel+TextStyle.h"
#import <objc/runtime.h>
@implementation UILabel (TextStyle)
+ (void) load {
Method method1 = class_getInstanceMethod([UILabel class], @selector(setText:)); Method method2 = class_getInstanceMethod([UILabel class],@selector(setTextString:));
method_exchangeImplementations(method1, method2);
}
- (void)setTextString:(NSString *)textString {
if (![textString isEqualToString:@"-"] && [textString hasPrefix:@"-"]) {
//对于负值进行标红处理
self.textColor = [UIColor redColor];
}
[self setTextString:textString];
}
@end
这里我就将setText:和setTextString:交换,之前使用label给text赋值的语句,其实全部调用的
是setTextString:方法给label赋值,这样就完成了对项目的修改。
场景2-动态扩展属性
OC中类可以通过Category来直接扩展方法,但是却不能直接通过添加属性来扩展属性(以我项目中用到的一个为例)。
这里需要使用到objc_setAssociatedObject()和objc_getAssociatedObject()方法;
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
objc_setAssociatedObject()的主要作用是:让一个对象和另一个对象关联起来,即一个对象保持对另一个对象的引用,并可以获取这个对象。关键字是一个void类型的指针。每个关键字必须是唯一的,通常都是会采用静态变量来作为关键字。
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key) OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);
#import <UIKit/UIKit.h>
@interface UIView (SPUtils)
@property(nonatomic) NSString * testString;
@end
#import "UIView+SPUtils.h"
#import <objc/runtime.h>
@implementation UIView (SPUtils)
-(void)setTestString:(NSString *)testString{
objc_setAssociatedObject(self, @selector(testString), testString,OBJC_ASSOCIATION_RETAIN);
}
-(NSString *)testString{
return objc_getAssociatedObject(self, _cmd);
}
@end
这样在使用在其他中创建UIView对象,可以直接使用testString属性了!
场景3-实现字典和模型的自动转换(MJExtension)
使用RunTime提供的函数遍历model自身的所有属性,如果属性在json中有对应的值,则将其复制。核心方法:在NSObject的分类中添加方法。
#import <Foundation/Foundation.h>
@interface NSObject (MutableCopy)
- (instancetype) initWithDict:(NSDictionary *)dict;
@end
#import "NSObject+MutableCopy.h"
#import <objc/runtime.h>
@implementation NSObject (MutableCopy)
- (instancetype) initWithDict:(NSDictionary *)dict{
if (self = [self init]) {
//(1)获取类的属性及属性对应的类型
NSMutableArray * keys = [NSMutableArray array];
NSMutableArray * attributes = [NSMutableArray array];
unsigned int outCount;
objc_property_t * properties = class_copyPropertyList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
objc_property_t property = properties[i];
//通过property_getName函数获得属性的名字
NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
[keys addObject:propertyName];
//通过property_getAttributes函数可以获得属性的名字和@encode编码
NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
[attributes addObject:propertyAttribute];
} //立即释放properties指向的内存
free(properties);
//(2)根据类型给属性赋值
for (NSString * key in keys) {
if ([dict valueForKey:key] == nil) continue;
[self setValue:[dict valueForKey:key] forKey:key];
}
}
return self;
}
@end
目前就RunTime就研究这么多,有兴趣的点个关注,关注不迷路额!!!喜欢的朋友可以关注个人微信公众号:IT科学技术