RunTime实现的反射

本文深入探讨了Objective-C的RunTime系统,详细解释了如何利用反射在运行时检查和修改类的行为。通过实例,展示了如何使用反射进行对象属性映射,增强了代码的灵活性和动态性。
Objective-C 中基于RunTime实现的反射
一、反射
反射,一般表现在字符串和Class转换,字符串和内部方法转换,字符串和属性的转换(取值和赋值)。
二、Objective-C中的反射
OC的反射是基于其Runtime实现的。
以执行某个函数为例,我们知道在OC中执行[pyPerson doSomething]函数,实质上是发送了一个消息给Runtime,然后Runtime再根据这个Class的字符串名和这个函数的字符串名,去匹配真正相应的方法的地址,然后再执行的。所以中间我们可以利用字符串去动态的检测,甚至动态的修改(之前说到的Method Swizzling)。


在OC中,很多Runtime的动态特性的接口大致都已经在NSObject.h中声明,可以自己看下源码。 
1.字符串和Class转换,及判断
Class __nullable NSClassFromString(NSString *aClassName);
-(BOOL)isKindOfClass:(Class)aClass;
-(BOOL)isMemberOfClass:(Class)aClass;
example:
//通过这样的方式获取class
Class Person = NSClassFromString(@"PYPerson");  
PYPerson *person= [[Person alloc] init]; 
//判断是否为其子类的对象
PYPerson *person= [[PYPerson alloc] init]; 
if([personisKindOfClass:[PYStudent class]]){ PYLog(@"person是PYStudent类型或其子类");
}else{ PYLog(@"person不是PYStudent类型或其子类"); } //判断是否是该class的对象if([person isMemberOfClass:[PYStudentclass]]){ PYLog(@"person是PYStudent类型"); }else{ PYLog(@"person不是PYStudent类型"); } 
2.字符串和内部方法转换
- (BOOL)respondsToSelector:(SEL)aSelector  判断类型或对象有没有某个方法
+ (BOOL)instancesRespondToSelector:(SEL)aSelector; //判断静态方法
- (id)performSelector:(SEL)aSelector  动态调用对象的方法
- (BOOL)conformsToProtocol:(Protocol *)aProtocol; 判断对象是否实现某个Protocol协议
example:
//动态生成方法选择器
SEL sel =  NSSelectorFromString(@"setAge:");  


//检测是否存在某方法
PYStudent *stu = [[PYStudent alloc]init];  
if([stu respondsToSelector:@selector(setAge)]){  
    PYLog(@"stu 有setAge这个方法");  
}else{  
    PYLog(@"没有");  
}  


//动态动用方法
PYStudent *stu = [[PYStudent alloc]initAge:1];  
int age = [stu performSelector:@selector(age)];  
PYLog(@"%i",age);//输出1  


//动态调用有参数的方法
[stu  performSelector:@selector(setAge:) withObject:@"2"]; 


3.字符串和属性的转换
OC中属性的反射通过KVC(Key-Value Coding)机制实现,KVC是一种间接访问对象属性的机制,不直接调用getter 和 setter方法,而使用valueForKey 来替代getter 方法,setValue:forKey来代替setter方法。
具体KVC使用的Example为:
PYPersion *persion = [[PYPersion alloc] init];
//不使用KVC
persion.name = @"yu" ;
//使用KVC的写法
[persion  setValue:@"yu" forKey:@"name"];
上面是利用KVC访问类里的某个属性,下面利用KVC直接访问类里的类里的某个属性
//不使用KVC
PYPersion *persion = [[PYPersion alloc] init];
PYPhone *phone = persion.phone;
PYBattery *battery = phone.battery;


//使用KVC
PYBattery *battery = [persion valueForKeyPath: @"phone.battery" ];


对于SetValueForKey,需要小心的是,假如类型匹配错误的情况下,编译会通过,但运行会报错


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值