Runtime根据字面意思就是运行时,它是一套纯c语言的API。而oc正好是一门运行时语言,那么运行时语言到底是什么鬼呢?
1 运行时语言:尽可能的将编译时要执行的逻辑推到了运行时。
a: 最常见的就是我们说的将数据类型的确定由编译推到了运行时。
b: 某个对象使用某个方法,到底使用什么方法在编译时是不确定的,要到运行时才能确定下来。这也就是为什么C语言如果调用未实现的函数在编译的时候就崩溃,但是OC语言会到运行的时候才会崩溃。
2 Runtime的使用场景
a : 获取到类的所有实例变量(公有+私有)等等
class_copyIvarList()
b : 获取到类的所有方法
class_copyMethodList()
c : 为分类添加属性
objc_setAssociatedObject()+objc_getAssociatedObject()
d : 实现方法交换
class_getInstanceMethod()+method_exchangeImplementations()
e : 实现字典和模型之间的互相转换
class_copyIvarList()
3:具体代码
a 功能1 获取到类的所有实例变量(公有+私有)等等
#import <Foundation/Foundation.h>
@interface Person : NSObject<NSCoding>
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)NSString *sex;
@property (nonatomic,strong)NSString *number;
- (void)sayHi;
@end
#import "Person+hello.h"
#import "Person.h"
#import <objc/message.h>
#import <objc/runtime.h>
@interface Person ()
@property (nonatomic,strong)NSString *address;
@end
@implementation Person
- (instancetype)init{
if (self = [super init]) {
self.name = @"明明";
self.sex = @"女";
self.number = @"123";
self.address = @"中南海";
}
return self;
}
- (void)sayHi{
NSLog(@"sayHi");
}
#import "Person.h"
#import "Person+hello.h"
#import <objc/message.h>
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//runtime功能1 获取到类的所有实例变量(公有+私有)等等
//创建person对象
Person *p = [[Person alloc]init];
unsigned int count = 0;
//获取到指向类的实例变量的指针
Ivar *ivars = class_copyIvarList([p class], &count);
for (int i = 0; i < count; i++) {
Ivar var = ivars[i];
const char *c = ivar_getName(var);
// NSLog(@"%s",c);
}
}
return 0;
}
b : 获取到类的所有方法
//main.m中 获取到类的所有方法
Method *methods = class_copyMethodList([p class], &count);
for (int i = 0; i < count; i++) {
Method method = methods[i];
SEL s = method_getName(method);
const char *name = sel_getName(s);
// NSLog(@"%s",name);
}
c : 为分类添加属性(个人觉得意义并不大,就使用oc也能做到,只是它不会关联到self)
#import "Person.h"
@interface Person (hello)
//分类添加的属性不会生成对应的实例变量
@property (nonatomic,strong)NSString *age;
@end
#import <objc/runtime.h>
#import "Person+hello.h"
@implementation Person (hello)
static const void *key = @"123";
- (void)setAge:(NSString *)age{
//对象关联
//self为要关联的对象
//key为要关联的变量
//age为要被关联的变量
//第四个参数为key修饰符
objc_setAssociatedObject(self, key, age, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)age{
//返回关联的对象
return objc_getAssociatedObject(self, key);
}
//main.m中使用此属性
p.age = @"123";
NSLog(@"%@",p.age);
d : runtime功能4 实现方法交换(当我们对系统方法的实现不满意的时候,我们可以通过方法交换来自定义实现)
#import "Person.h"
@interface Person (hello)
- (void)play;
@end
#import <objc/runtime.h>
#import "Person+hello.h"
@implementation Person (hello)
+ (void)load{
//获取到方法
Method sayHi = class_getInstanceMethod([self class], @selector(sayHi));
Method play = class_getInstanceMethod([self class], @selector(play));
//实现方法交换
method_exchangeImplementations(sayHi, play);
}
//实现方法play和sayHi方法的交换
- (void)play{
NSLog(@"play");
}
//在main.m中调用可以看到打印出来 play
[p sayHi];
e: 实现字典和模型之间的互相转换
Person *p = [[Person alloc]init];
//定义一个字典用来赋值给model
NSDictionary *dic = @{
@"name" : @"隔壁老王",
@"sex":@"男",
@"number":@"1111",
@"address":@"😄"
};
//定义一个空字典用来存储model
NSMutableDictionary *dic1 = [NSMutableDictionary dictionary];
//用来存储实例变量的个数
unsigned int count = 0;
//获取到指向类的实例变量的指针
Ivar *ivars = class_copyIvarList([p class], &count);
//遍历
for (int i = 0; i < count; i++) {
Ivar var = ivars[i];
const char *c = ivar_getName(var);
//获取到字符串
NSString *s = [NSString stringWithUTF8String:c];
//去除下划线(_)
NSString *s1 = [s substringFromIndex:1];
//a 将模型和字典对应
id value = [p valueForKey:s1];
[dic1 setValue:value forKey:s1];
//b 将字典和模型对应
[p setValue:dic[s1] forKey:s1];
}
NSLog(@"dic1 = %@",dic1);