runtime是OC比较底层的东西,而我们在学OC的时候很容易忽视runtime的学习,但是runtime的熟悉还是很有必要的,他可以使你更了解底层的封装,从而对OC的理解更加深入(比如成员变量的本质就是一个结构体)
1.关于成员变量
首先建一个类,加入叫Person,在类下面导入runtime框架
#import <objc/runtime.h>
在这里首先介绍下runtime关于成员的相关属性
Ivar *class_copyIvarList(Class cls, unsigned int *outCount) //获取所有成员变量
const char *ivar_getName(Ivar v) //获取某个成员变量的名字
const char *ivar_getTypeEncoding(Ivar v) //获取某个成员变量的类型编码
Ivar class_getInstanceVariable(Class cls, const char *name) //获取某个类中指定名称的成员变量
id object_getIvar(id obj, Ivar ivar) //获取某个对象中的某个成员变量的值
void object_setIvar(id obj, Ivar ivar, id value) //设置某个对象的某个成员变量的值
我们来操作一下
首先创建成员变量
@property(nonatomic,strong)NSString * name;
@property(nonatomic,strong)NSString * gender;
@property(nonatomic,assign)NSNumber* age;
@property(nonatomic,assign)NSInteger height;
①利用runtime得到成员变量的属性
-(NSString*)description
{
unsigned int outCount;
//获取所有的成员变量
//class 要获取的某个类名,outCount:通过这一个函数执行之后将成员变量的个数赋值到此
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
//每次获取一个成员变量
Ivar ivar = ivarList[i];
//打印成员变量的名字和编码类型
NSLog(@"name = %s,type = %s",ivar_getName(ivar),ivar_getTypeEncoding(ivar));
}
return nil;
}
②利用runtime给成员变量赋值
首先在Person.h文件定义一个方法
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age height:(NSInteger)height;
在Person.m文件实现
+ (Person *)personWithName:(NSString *)name gender:(NSString *)gender age:(NSNumber *)age height:(NSInteger)height
{
Person *person = [Person new];
unsigned int outCount;
Ivar *ivarList = class_copyIvarList(self,&outCount);
//obj:要设置的对象, ivar:压迫设置的对象的某一个属性 value:value
object_setIvar(person,ivarList[0],name);
object_setIvar(person,ivarList[1],gender);
object_setIvar(person,ivarList[2],age);
object_setIvar(person,ivarList[3],@(height));
return person;
}
③得到成员变量的值
在person.h里设置方法
- (void)getPersonMessager;
在Person.m里实现
- (void)getPersonMessager
{
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
NSLog(@"name = %s,value = %@",ivar_getName(ivarList[i]),object_getIvar(self, ivarList[i]));
}
}
2.关于实例方法
runtime的属性:
1 + resolveInstanceMethod:(SEL)sel // 为一个实例方法动态添加实现
2 + resolveClassMethod:(SEL)sel // 为一个类方法动态添加实现
3 - (id)forwardingTargetForSelector:(SEL)aSelector
//为没有实现的方法指定一个对象
4 - (void)forwardInvocation:(NSInvocation *)anInvocation
//子类重载这个方法为消息指定其他对象
具体的用法
①
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"walkOnTheStreet:"]) {
//为一个没有实现的方法是动态添加实现
cls:类
name:没有实现的方法
IMP:要添加的实现
types:动态添加的实现的类型编码
class_addMethod(self, @selector(walkOnTheStreet:), (IMP)walkFunc, "V@:@");
//Void 对应类型编码V ,对象类型是 @
}
return [super resolveInstanceMethod:sel];
}
②切换消息转化对象:把Person的方法转移到Dog里实现
在Person里设置方法
- (void)walkOnTheStreet1
在Dog里定义一个一样的方法
- (void)walkOnTheStreet1
在Dog.m里实现
- (void)walkOnTheStreet1
{
NSLog(@"you are dog!!!!!!--%s",__func__);
}
在Person.m里转移
方法1
- (void)orwardInvocation:(NSInvocation *)anInvocation
{
//判断Dog显影方法
if ([Dog instancesRespondToSelector:anInvocation.selector]) {
self.dog= [Dog new];
[anInvocation invokeWithTarget:self.dog];//taget
}
}
方法1
//给方法1指定一个有效的签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
if (!methodSignature) {
methodSignature = [Dog instanceMethodSignatureForSelector:aSelector];
}
return methodSignature;
}
方法2
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSString *selString = NSStringFromSelector(aSelector);
if ([selString isEqualToString:@"walkOnTheStreet1"]) {
self.dog = [Dog new];
return self.dog;
}
//如果方法没有响应
return [super forwardingTargetForSelector:aSelector];
}