runtime:是一套底层的C语言API,包含很多强大实用的C语言数据类型和C语言函数,平时我们编写的OC代码,底层都是基于runtime实现的。
常用头文件:
#import <objc/runtime.h>
#import <objc/message.h>
objc_msgSend
Objective-C 中的方法调用,不是简单的方法调用,而是发送消息,如:
TestClass *objct = [[TestClass alloc] init];
[objctshowName:@"Tom"];
转化为:
((void (*) (id, SEL, NSString *)) objc_msgSend) (objct, sel_registerName(
"showName:"),
@"Tom");
objc_msgSend 在使用时都被强制转换了一下,这是因为 objc_msgSend 函数可以传各种不同的返回值以及多个参
数,但默认情况
下是没有参数和返回值的。
class_copyIvarList:返回一个指向类的成员变量数组的指针
class_copyIPropertyList:返回一个指向类的属性数组的指针
上面两个方法返回的指针,在使用完毕之后必须free()。
开发中使用:
归档:
- (void)encodeWithCoder:(NSCoder *)aCoder{
unsigned int outCount = 0;
Ivar *vars = class_copyIvarList([self class], &outCount);
for
(int i = 0; i < outCount; i ++) {
Ivar
var
= vars[i];
const char *name = ivar_getName(
var
);
NSString *key = [NSString stringWithUTF8String:name];
// 注意kvc的特性是,如果能找到key这个属性的setter方法,则调用setter方法
// 如果找不到setter方法,则查找成员变量key或者成员变量_key,并且为其赋值
// 所以这里不需要再另外处理成员变量名称的“_”前缀
id value = [self valueForKey:key];
[aCoder encodeObject:value forKey:key];
}
free(vars);
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder{
if
(self = [
super
init]) {
unsigned int outCount = 0;
Ivar *vars = class_copyIvarList([self class], &outCount);
for
(int i = 0; i < outCount; i ++) {
Ivar
var
= vars[i];
const char *name = ivar_getName(
var
);
NSString *key = [NSString stringWithUTF8String:name];
id value = [aDecoder decodeObjectForKey:key];
[self setValue:value forKey:key];
}
free(vars);
}
return
self;
}
//字典转模型
id objc = [[self alloc] init];
for
(NSString *key
in
aDictionary.allKeys) {
id value = aDictionary[key];
/*判断当前属性是不是Model*/
objc_property_t property = class_getProperty(self, key.UTF8String);
unsigned int outCount = 0;
objc_property_attribute_t *attributeList = property_copyAttributeList(property,
&outCount);
objc_property_attribute_t attribute = attributeList[0];
NSString *typeString = [NSString stringWithUTF8String:attribute.value];
if
([typeString isEqualToString:@
"@\"TestModel\""
]) {
value = [self objectWithKeyValues:value];
}
/**********************/
//生成setter方法,并用objc_msgSend调用
NSString *methodName = [NSString stringWithFormat:@
"set%@%@:"
,
[key substringToIndex:1].
uppercaseString,[key substringFromIndex:1]];
SEL setter = sel_registerName(methodName.UTF8String);
if
([objc respondsToSelector:setter]) {
((void (*) (id,SEL,id)) objc_msgSend) (objc,setter,value);
}
free(attributeList);
}
return
objc;
}
//模型转字典
-(NSDictionary *)keyValuesWithObject{
unsigned int outCount = 0;
objc_property_t *propertyList = class_copyPropertyList([self class], &outCount);
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for
(int i = 0; i < outCount; i ++) {
objc_property_t property = propertyList[i];
//生成getter方法,并用objc_msgSend调用
const char *propertyName = property_getName(property);
SEL getter = sel_registerName(propertyName);
if
([self respondsToSelector:getter]) {
id value = ((id (*) (id,SEL)) objc_msgSend) (self,getter);
/*判断当前属性是不是Model*/
if
([value isKindOfClass:[self class]] && value) {
value = [value keyValuesWithObject];
}
/**********************/
if
(value) {
NSString *key = [NSString stringWithUTF8String:propertyName];
[dict setObject:value forKey:key];
}
}
}
free(propertyList);
return
dict;
}
交换方法
method_exchangeImplementations(Method m1, Method m2),一般用自己写的方法(常用在自己写的框架
中,添加某些防错措施)
来替换系统的方法实现
Method orginalMethod = class_getInstanceMethod(NSStringFromClass(@__NSArray),@selector(addObject:));
Method newMethod = class_getInstanceMethod(NSStringFromClass(@__NSArray), @selector(new_addObject:));
method_exchangeImplementations(orginalMethod, newMethod);