Runtime:运行时
使用Runtime就是使用苹果提供的API
使用Runtime可以实现OC无法实现的:
1.使用Runtime在程序运行时,动态创建类;
2.使用Runtime在程序运行时,动态的添加、修改、删除对象的方法和属性;
3.使用Runtime在程序运行时,遍历对象或类的所有成员属性和成员方法。
使用Runtime需要导入<objc/runtime.h>或<objd/message.h>(<objd/message.h>的头文件中默认包含<objc/runtime.h>)
在Runtime中
Ivar 代表属性;Method 代表方法。
使用Runtime可以交换类方法的实现,如:NSURL的urlWithString后面的string如果好友中文等无效字符生成的url就会为nil,这时候进行请求的时候就会崩溃,不想每次请求之前都判断url是否为空的话,就在NSURL的分类中使用Runtime替换掉NSURL的urlWithString的方法实现:
// 思路:通过Runtime交换方法的实现
#import "NSURL+HRURL.h"
#import
@implementation NSURL (HRURL)
//NSURL+HRURL.h这个类被加载的时候调用这个方法
+(void)load{
//利用Runtime交换两个方法的实现
// method_exchangeImplementations(Method _Nonnull m1, Method _Nonnull m2)
// class_getClassMethod(, ) 获取类方法 +
// class_getInstanceMethod(, )获取对象方法 -
//获取要交换的方法
Method URLWithString = class_getClassMethod([NSURL class], @selector(URLWithString:));
Method HR_URLWithString = class_getClassMethod([NSURL class], @selector(HR_URLWithString:));
//交换两个方法的实现
method_exchangeImplementations(URLWithString, HR_URLWithString);
}
// +(instancetype)URLWithString:(NSString *)URLString{
// NSURL *url = [[NSURL alloc]initWithString:URLString];
// if(url == nil){
// NSLog(@"url为空 ===== %@",url);
// }
// return url;
// }
//此时的HR_URLWithString方法调用的实现方法是系统URLWithString方法实现
+(instancetype)HR_URLWithString:(NSString *)str{
//这时应该调用系统的方法实现,而系统的方法实现已经交换到了自定义方法下,所以实现的时候需要调用自定义的方法
NSURL *url = [NSURL HR_URLWithString:str];
if(url == nil){
NSLog(@"url为空 ===== %@",url);
}
return url;
}
也可以使用Runtime简化归档接档,主要使用了Runtime在程序运行时可以便利对象的成员属性,从而获取对象成员属性的总数以及key值,再根据KVO获取属性的value值,使用for循环对模型进行便利,循环中进行归档和解档的操作,项目中使用这个工具类就可以轻松归档解档成员变量比较多的模型了:
#import "Person.h"
#import <objc/message.h>
@implementation Person
//当外界归档这个对象的时候就会调用这个方法,不实现就会报错
- (void)encodeWithCoder:(NSCoder *)coder
{
// [coder encodeObject:_name forKey:@"name"];
// [coder encodeInt:_age forKey:@"age"];
//思路:使用for循环遍历出所有的属性,利用Runtime获取属性的数量和属性的key值,利用KVO根据key值得到属性的value值
//Runtime
unsigned int count = 0;
Ivar * ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i ++) {
//取出成员变量
Ivar ivar = ivars[i];
//通过Ivar拿到key
const char *name = ivar_getName(ivar);
NSString *key = [NSString stringWithUTF8String:name];
//通过KVC拿到属性的值
[coder encodeObject:[self valueForKey:key] forKey:key];
}
//在C中,但凡用到了New,Creat,copy这样的函数(都会reten一次),都需要释放一下指针
free(ivars);
}
//当外界接档的时候调用这个方法
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super init];
if (self) {
// _name = [coder decodeObjectForKey:@"name"];
// _age = [coder decodeIntForKey:@"age"];
//Runtime
unsigned int count = 0;
Ivar * ivars = class_copyIvarList([Person class], &count);
for (int i = 0; i < count; i ++) {
//取出成员变量
Ivar ivar = ivars[i];
//通过Ivar拿到key
const char *name = ivar_getName(ivar);
NSString *key = [NSString stringWithUTF8String:name];
//解挡
id value = [coder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
free(ivars);
}
return self;
}
@end