上来直接就写代码
一.获取属性列表并修改其中属性的值:
unsigned int count = 0;
// 获取person里的所有属性 包括私有属性
Ivar *ivar = class_copyIvarList([p class], &count);
NSLog(@"打印出Person里所有属性(包括私有属性):");
for (int i=0; i<count; i++) {
Ivar tmpIvar = ivar[I];
//通过ivar_getName获取属性名字
NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(tmpIvar)];
NSLog(@"%@",ivarName);
if ([ivarName isEqualToString:@"_address"]) {
//通过object_setIvar修改属性address的值为CN
object_setIvar(p, tmpIvar, @"CN");
}
}
二.动态添加属性
在OC里是不允许直接为一个category添加属性的,但是我们可以通过runtime的方式动态添加,下面是一个为NSString 添加一个name属性的例子
static void *nameKey = &nameKey;
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY);
}
objc_setAssociatedObject 设置关联对象
- (NSString *)name {
return objc_getAssociatedObject(self, &nameKey);
}
objc_getAssociatedObject 获取关联对象
这样就可以在使用这个category的地方为name这个属性赋值了。
三. 获取类的所有方法
通过class_copyMethodList方法可以获取一个类所有的方法。代码如下:
- (NSMutableArray *)getAllMethods:(Class)class {
unsigned int count = 0;
Method *methods = class_copyMethodList(class, &count);
NSMutableArray *tmp = @[].mutableCopy;
for (int i=0; i<count; i++) {
Method method = methods[i];
// IMP imp = method_getImplementation(method);
SEL sel = method_getName(method);
const char *selName = sel_getName(sel);
const char *encoding = method_getTypeEncoding(method);
NSString *result = [NSString stringWithFormat:@"方法名:%@, 参数个数:%d, 编码方式:%@",[NSString stringWithUTF8String:selName],method_getNumberOfArguments(method),[NSString stringWithUTF8String:encoding]];
[tmp addObject:result];
}
return tmp;
}
先获取方法列表,再遍历得到Method,再通过method_getName获取SEL ,然后使用sel_getName方法获取到SEL Name。
当然也可以获取到需要传入的参数个数以及参数的编码方式。
四.动态添加方法
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
class_addMethod([Person class], @selector(eat), (IMP)eatFoods, "v@:");
});
void eatFoods(id self, SEL _cmd) {
NSLog(@"eat foods");
}
上述代码,动态的为Person类添加了一个eat的方法, eatFoods是这个方法的实现,也就是他的指针地址
"v@:" 意思是,v 代表无返回值 void,如果是 i 则代表 int;@代表 id sel; : 代表 SEL _cmd;
“v@:@@” 意思是,两个参数的没有返回值。
五. 交换两个方法
以下是交换两个实例方法:
Method method1 = class_getInstanceMethod(p.class, @selector(personMethod));
Method method2 = class_getInstanceMethod(p.class, @selector(fetchNameMethod));
method_exchangeImplementations(method1, method2);
class_getInstanceMethod 的意思是获取实例方法
以下是交换两个类方法:
Method method3 = class_getClassMethod([Person class], @selector(niceShot));
Method method4 = class_getClassMethod([Person class], @selector(badShot));
method_exchangeImplementations(method3, method4);
class_getClassMethod 的意思是获取类方法;
当然两个方法不在同一个类里也是可以互换的,这个只是交换了两个SEL的IMP(指针地址)!
上述只是runtime的一些基础使用方法, 当然它的功能还不仅仅局限于这些,大家可以看看苹果爸爸的官方文档:runtime 官方文档
整理的小Demo: github
网友评论