iOS-Runtime原理及使用
Runtime原理
1.Runtime简称运行时.OC就是运行时机制,(就是系统在运行的时候的一些机制)其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数.对于OC的函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用.
2.它是一个主要使用C和汇编写的库,为C添加了面相对象的能力并创造了Objective-C.这就是说它在类信息(Class information)中被加载,完成所有的方法分发,方法转发,等等.Objective-C runtime 创建了所有需要的结构体,让Objective-C 的面相对象编程变为可能.
3.是一套比较底层的纯C语言API,属于1个C语言库, 包含了很多底层的C语言API.在我们平时编写的OC代码中,程序运行过程时,其实最终都是转成了runtime的C语言代码,runtime算是OC的幕后工作者.
4.因为Objc是一门动态语言,所以它总是想办法把一些决定工作从编译连接推迟到运行时.也就是说只有编译器是不够的,还需要一个运行时系统(runtime system)来执行编译后的代码.这就是 Objective-C Runtime 系统存在的意义,它是整个Objc运行框架的一块基石.
5.Mac和iPhone开发者关心的有两个runtime:Modern Runtime(现代的 Runtime)和 Legacy Runtime(过时的Runtime).Modern Runtime:覆盖所有 64 位的 Mac OS X 应用和所有 iPhone OS 的应用.Legacy Runtime:覆盖其他的所有应用(所有32位的 Mac OS X 应用)Method有2种基本类型的方法.Instance Method(实例方法).Class Method(类方法)
Runtime简单使用
Person.h
@interface Person : NSObject
@property(nonatomic,copy)NSString *name;
@property(nonatomic,copy)NSString *gender;
@property(nonatomic,assign)NSInteger age;
-(void)eat;
-(void)play;
@end
Person.m
#import "Person.h"
@implementation Person
-(void)eat{
NSLog(@"%@吃饭",self.name);
}
-(void)play{
NSLog(@"%@玩",self.name);
}
@end
先导入头文件
#import "RuntimeViewController.h"
#import "Person+Runtime.h"
#import "Person.h"
#import <objc/message.h>//包含消息机制
#import <objc/runtime.h>//包含对类、成员变量、属性、方法的操作
@interface RuntimeViewController ()
@end
@implementation RuntimeViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setTitle:@"runTime"];//动态添加属性,修改属性值(类别"Person+Runtime.h")
[self exchangeAttribute];//
// [self performSelector:@selector(likePlay)];
objc_msgSend(self,@selector(likePlay));// 动态调用方法(在 LLVM 6.0 中增加了一个 OBJC_OLD_DISPATCH_PROTOTYPES,默认配置在 Apple LLVM 6.0 - Preprocessing 中的 Enable Strict Checking of objc_msgSend Calls 中为Yes 改成NO;)
[self getAttribute];// 利用runtime遍历一个类的全部成员变量
[self controlVariables];// 动态控制变量
[self addMethod];//动态添加方法
[self exchangeMethod];//动态交换方法实现
}
1.动态为Category扩展加属性
Person+Runtime.h
#import "Person.h"
@interface Person (Runtime)
@property(nonatomic,copy)NSString *height;// 身高
-(void)setHeight:(NSString *)height;
-(NSString *)height;
-(NSString *)addStr1:(NSString *)str1 str2:(NSString *)str2;
@end
Person+Runtime.m
#import "Person+Runtime.h"
#import <objc/message.h>//包含消息机制
#import <objc/runtime.h>//包含对类、成员变量、属性、方法的操作
@implementation Person (Runtime)
static char * heightKey = "heightKey";
-(void)setHeight:(NSString *)height{
objc_setAssociatedObject(self, heightKey, height, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(NSString *)height{
return objc_getAssociatedObject(self, heightKey);
}
-(NSString *)addStr1:(NSString *)str1 str2:(NSString *)str2{
return [str1 stringByAppendingString:str2];
}
@end
方法实现
-(void)exchangeAttribute{
Person *p = [[Person alloc]init];
p.height = @"178";
NSLog(@"身高==%@",p.height);
}
打印结果
2016-10-24 10:45:09.003 WsBlog[11181:4616582] 身高==178
2.动态控制变量
-(void)controlVariables{
Person * p = [Person new];
p.name = @"wym";
NSLog(@"%@",[p name]);
unsigned int count;
//Ivar表示类中的实例变量。Ivar其实就是一个指向objc_ivar结构体指针,它包含了变量名(ivar_name)、变量类型(ivar_type)等信息。
Ivar *ivar = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i ++) {
Ivar var = ivar[i];
const char *varName = ivar_getName(var);
NSString *name = [NSString stringWithCString:varName encoding:NSUTF8StringEncoding];
if ([name isEqualToString:@"_name"]) {
object_setIvar(p, var, @"ws");
break;
}
}
NSLog(@"%@",p.name);
}
打印结果
2016-10-24 10:45:09.004 WsBlog[11181:4616582] wym
2016-10-24 10:45:09.004 WsBlog[11181:4616582] ws
3.利用runtime动态遍历一个类的全部成员变量
-(void)getAttribute{
//1.导入头文件 <objc/runtime.h>
unsigned int count = 0;
//获取指向该类所有属性的指针
objc_property_t *propeprties = class_copyPropertyList([Person class], &count);
for (int i = 0; i < count; i++) {
//获得
objc_property_t property = propeprties[i];
//根据objc_property_t 获取所有属性的名称--->C语言的字符串
const char *name = property_getName(property);
NSString *attributeName = [NSString stringWithUTF8String:name];
NSLog(@"%d-----%@",i,attributeName);
}
}
打印结果
2016-10-24 10:45:09.003 WsBlog[11181:4616582] 0-----height
2016-10-24 10:45:09.003 WsBlog[11181:4616582] 1-----name
2016-10-24 10:45:09.004 WsBlog[11181:4616582] 2-----gender
2016-10-24 10:45:09.004 WsBlog[11181:4616582] 3-----age
4.动态添加方法
void goHome(id self, SEL _cmd){
NSLog(@"回家");
}
- (void)addMethod
{
Person *p = [Person new];
p.name = @"ET";
class_addMethod([Person class], @selector(shise), (IMP)goHome, "v@:");
[p performSelector:@selector(shise) withObject:nil];
}
打印结果
2016-10-24 10:45:09.004 WsBlog[11181:4616582] 回家
5.动态交换方法实现
-(void)exchangeMethod{
Person *p = [[Person alloc]init];
p.name = @"ET";
[p eat];
[p play];
// 实现方法交换
Method m1 = class_getInstanceMethod([Person class], @selector(eat));
Method m2 = class_getInstanceMethod([Person class], @selector(play));
method_exchangeImplementations(m1, m2);
[p eat];
[p play];
}
打印结果
2016-10-24 10:45:09.004 WsBlog[11181:4616582] ET玩
2016-10-24 10:45:09.005 WsBlog[11181:4616582] ET吃饭
2016-10-24 10:45:09.008 WsBlog[11181:4616582] ET吃饭
2016-10-24 10:45:09.008 WsBlog[11181:4616582] ET玩
6.动态调取方法
-(void)likePlay{
NSLog(@"喜欢玩");
}
打印结果
2016-10-24 10:45:09.003 WsBlog[11181:4616582] 喜欢玩