runtime 的基本使用场景

在实际开发中,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];

}

值得注意的是,这个方法是在运行时动态调用的,所以编译的时候会有警告。

你可能感兴趣的:(runtime 的基本使用场景)