Runtime 在我们开发中可能用到的不多,但是有些时候,它却可以帮我们快速的完成一些特殊的需求,这两天看了一些Runtime的几个简单功能,记录一下。
我们所说的Runtime是苹果给我们提供的C语言API,它给我们提供了很多的函数,让我们可以在我们的项目中可以有一些非常底层实际性的操作.Runtime可以让我们去动态的修改内存里的一些东西,譬如被执行的代码,创建的对象,图片等.下面通过两个例子记录一下Runtime的一些简单功能。
首先,Runtime可以动态的获取我们OC对象的属性,下面我们通过我们平常常用到的归档解档操作,来看一下用Runtime是怎么实现的。
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
if(self == [super init])
{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0 ; i < count; i ++) {
//获取相应下标的ivar
Ivar ivar = ivars[i];
const char * name = ivar_getName(ivar);
//将const char * 转换成UTF8 获取属性名
NSString *varName = [NSString stringWithUTF8String:name];
//获取属性相应的值
id value = [aDecoder decodeObjectForKey:varName];
[self setValue:value forKey:varName];
}
free(ivars);
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int count = 0;
Ivar *ivars = class_copyIvarList([self class], &count);
for (int i = 0; i < count; i ++) {
Ivar ivar = ivars[i];
const char * name = ivar_getName(ivar);
//将const char * 转换成UTF8 获取属性名
NSString *varName = [NSString stringWithUTF8String:name];
[aCoder encodeObject:[self valueForKey:varName] forKey:varName];
}
free(ivars);
}
同时可以根据Runtime获取属性名称的这一功能实现字典和模型的相互转换
用runtime提供的函数遍历Model自身所有属性,如果属性在json中有对应的值,则将其赋值。代码如下:
- (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;
}
Runtime可以用来替换方法,iOS中URLWithString不能直接加载中文,但是也不会报错,这个时候我们可以替换系统的URLWithString方法,在出现中文的时候给出相应的提示,代码如下
+(void)load
{
/*
交换方法实现
class_getInstanceMethod 获取实例方法
class_getClassMethod 获取类方法
method_exchangeImplementations 交换
*/
Method URLMet = class_getClassMethod(self, @selector(URLWithString:));
Method SKMet = class_getClassMethod(self, @selector(SK_URLWithString:));
method_exchangeImplementations(URLMet, SKMet);
}
+ (instancetype)SK_URLWithString:(NSString *)URLString
{
NSURL *url = [NSURL SK_URLWithString:URLString];//因为上面已经交换了,所以这里实际调用的是系统的方法实现
if(url == nil)
{
//这里可以提示自己想要的提示
NSLog(@"URL 为空");
}
return url;
}