在实际开发中,runtime最常用的场景就是交换方法、归档、字典转模型、动态生成属性方法、添加类方法等
(一)runtime交换方法
1.创建一个类的分类
2.导入
3.实现交换并且自定义方法
[objc]
//由于交换方法我们希望在工程运行期间只执行一次,所以通常写在load里面
[objc]
+ (void)load {
Method imageMethodNamed = class_getClassMethod(self,@selector(imageNamed:));
Method myImageMethodNamed = class_getClassMethod(self,@selector(myImageNamed:));
//实现两个方法的交换
method_exchangeImplementations(myImageMethodNamed,imageMethodNamed);
}
+(instancetype)customImageNamed:(NSString*)name {
//实际调用的是imageNamed:
UIImage*image = [UIImagecustomImageNamed:name];
//*此处为自定义配置*
returnimage;
}
(二)runtime动态生成getter、setter
由于在类目中添加属性不自动生成setter和getter方法,如果在.m文件中使用@dynamic配置起来就较为繁琐,如果一定要在类目中添加属性,我们可以使用runtime关联方法,简单方便。
比如在类目.h文件中声明了score属性,在.m文件中如下实现:
[objc]
void void *key;
- (void)setScore:(float)score {
//关联引用
/**
* 1.给哪个对象属性进行关联
* 2.用来保存传入的值的指针(用于get方法获取值)
* 3.传入的值(注意是对象类型)
* 4.关联引用的策略(这个根据属性添加的修饰而定)
*/
objc_setAssociatedObject(self, key, @(score), OBJC_ASSOCIATION_ASSIGN);
}
-(float)score {
idscore = objc_getAssociatedObject(self, key);
return[scorefloatValue];
}
(三)runtime归档、解档
归解档可以用kvc模式进行操作,但是如果属性过多的话,这样就显得极为繁琐而且容易出错,所以用runtime实现更为的科学和简洁。
[objc]
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder {
//获取某个类的所有成员变量
unsigned int count = 0;
Ivar*ivarList = class_copyIvarList([selfclass], &count);
//归档
for(inti = 0; i < count; i ++) {
Ivar aIvar = ivarList[i];
//获取成员变量的名称
constcharchar*iVarName = ivar_getName(aIvar);
idvalue = [selfvalueForKey:[NSStringstringWithUTF8String:iVarName]];
if (!value) {
}else {
[aCoderencodeObject:valueforKey:[NSStringstringWithUTF8String:iVarName]];
}
}
}
//解档
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
if(self= [superinit]) {
unsigned int count = 0;
Ivar *ivarList = class_copyIvarList([self class], &count);
for(inti = 0; i < count; i ++) {
Ivar aIvar = ivarList[i];
constcharchar*name = ivar_getName(aIvar);
idvalue = [aDecoderdecodeObjectForKey:[NSStringstringWithUTF8String:name]];
if (!value) {
}else {
[selfsetValue:valueforKey:[NSStringstringWithUTF8String:name]];
}
}
}
returnself;
}
(四)runtime字典转模型
这里需要注意的是,该方法只适用于字典的键和模型的属性一一对应的情况,如果要处理不一一对应的情况,最简单的解决方法是使用三方。
[objc]
+ (instancetype)modelWithDictionary:(NSDictionary *)dic {
Student*aStudent = [Studentnew];
unsigned int count = 0;
objc_property_t*propertyList = class_copyPropertyList([selfclass], &count);
for(inti = 0; i < count; i ++) {
objc_property_t aProperty = propertyList[i];
//获取属性名
constcharchar*name = property_getName(aProperty);
idvalue = dic[[NSStringstringWithUTF8String:name]];
if (!value) {
}else {
//使用kvc给属性赋值
[aStudentsetValue:valueforKey:[NSStringstringWithUTF8String:name]];
}
}
returnaStudent;
}
(五)runtime添加类方法
[objc]
void study(id reccevier, SEL sel) {
}
// 如果调用的方法没有实现,就会走这个方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if(sel ==@selector(study)) {
class_addMethod(self,@selector(study), (IMP)study,"v@:");
}
return [superresolveInstanceMethod:sel];
}
值得注意的是,这个方法是在运行时动态调用的,所以编译的时候会有警告。