IOS开发第二天-Object-c反射机制

获取Class

在OC中每一个类都有一个对应的Class,Object-C程序中获得Class通常有如下3中方式:

  1. 使用Class NSClassFromString(NSString* aClassName)函数来获取Class,该函数需要传入字符串参数,该字符串参数的值为某个类的类名。
  2. 调用某个类的class方法来获得对应的Class。
  3. 调用某个对象的class方法,由于该方法是NSObject类中的一个方法,所以所有的Object-C对象都可以调用该方法,该方法返回该对象所属类对应的Class。
  在3中方法中,第二种最安全,程序性能最好。但是如果我们只能得到一个类的字符串描述,那么只能使用第一种方式。

    Class class=NSClassFromString(@"NSDate");
        NSLog(@"%@",class);
        id date=[[class alloc]init];
        NSLog(@"%@",date);
        
        NSLog(@"%@",[date class]);
        
        NSLog(@"%d",class==NSDate.class);
以上测试了3种方法来创建class,得到的结果为:

---------------------------------------------------------------------------------------------------------------------------------

2017-04-11 17:45:16.340 Prj4[1118:1266051] NSDate

2017-04-11 17:45:16.346 Prj4[1118:1266051] 2017-04-11 09:45:16 +0000

2017-04-11 17:45:16.346 Prj4[1118:1266051] __NSDate

2017-04-11 17:45:16.347 Prj4[1118:1266051] 1

Program ended with exit code: 0

---------------------------------------------------------------------------------------------------------------------------------

可以看到,利用[data class]得到的是_NSDate而不是NSDate,这个是由于程序直接调用date对象的class方法来获取Class时返回NSDate的子类。NSDate只是这个类簇的前端,当程序调用[[NSDate alloc] init]创建对象时,程序返回的只是NSDate的子类实例。

检查继承关系

如果程序只需要确认一个类的继承关系,比如判断它是否是某个类的实例或是否为某个类及其子类的实例,可以利用NSObject提供的如下方法:

  1. isKindOfClass:该方法需要传入一个Class参数,用于判断该对象是否为该类及其子类的实例;
  2. isMemberOfClass:该方法需要传入一个Class参数,用于判断该对象是否为该类的实例;
  3. conformsToProtocol:该方法需要传入一个Protocol参数,用于判断该对象是否为该类及其子类的实例。
在第三个函数中,需要传入一个Protocol参数,通过下面的两个方法来获取对应的协议。

  1. 利用@protocol指令来实现     //@protocol(协议名);
  2. 调用Protocol* NSProtocolFromString:(NSString*) nameStr  //根据协议名来获取到对应的协议。

当得到对应的类以后,便可以利用KVC机制来进行对方法或者变量的调用。此时,无论变量或者函数出于什么访问权限,或者出于什么位置,均可以利用KVC机制来进行设置、访问实例变量的值。

如果程序需要判断某个对象是否可调用方法,可通过NSObject的respondsToSelector方法来进行判断。该方法传入一个sel参数,sel即为一个函数。为了动态获取到SEL对象,OC提供了@selector指令来获取当前类中指定的方法,需要方法的完整签名。根据字符串获取SEL: NSSelectorFromString(NSString* aSeletcorName).

 注意:@selector获取的是当前类中所指定的方法,@selector()基本可以等同C语言的中函数指针,只不过C语言中,可以把函数名直接赋给一个函数指针,而Object-C的类不能直接应用函数指针,这样只能做一个@selector语法来取.

@selector返回一个SEL对象。

[object @selector(方法名:方法参数..) ] 返回object对应类相应的方法。

SEL class_func ; //定义一个类方法指针
class_func = @selector(add:int);

执行selector值
取得相应值后,怎么处理SEL值呢,这一点仍然与函数指针一样,就是执行它
函数指针执行,(以下有几种等效形式)
*c_func(10);
c_func(10);
SEL变量的执行要用performSelecor方法来执行.
[对象 performSelector:SEL变量 withObject:参数1 withObject:参数2];

selector的应用场合
selector本质是跟C的回调函数一样。主要用于两个对象之间进行松耦合的通讯.这种方法基本上整个Cocoa库之间对象,控制之间通讯都是在这个基础构建的。

如果程序需要动态调用对象的普通方法,可以通过下面的方法:

  1. 通过利用NSObject提供的performSelector方法来实现,如果需要传入参数,还可以通withObject标签来传入参数。
  2. 使用objc_msgSend(receiver,selector,...)函数来调用。第一个参数是调用者,第二个参数代表调用的方法,接下来的参数代表要传入的参数。需要导入#import <obj/message.h>头文件。

案例代码如下:

#import <Foundation/Foundation.h>

@interface LWBCar2 : NSObject

@end
LWBCar2.m文件如下:

#import "LWBCar2.h"
#import<objc/message.h>
#import <objc/runtime.h>

@implementation LWBCar2
-(void) move:(NSNumber*) count{
    int num=[count intValue];
    for (int i=0; i<num; i++) {
        NSLog(@"%@",[NSString stringWithFormat:@"汽车正在路上走~~%d",i]);
    }
}

-(double) addSpeed:(double) factor{
    [self performSelector:@selector(move:) withObject:[NSNumber numberWithInt:2]];
    [self performSelector:NSSelectorFromString(@"move:") withObject:[NSNumber numberWithInt:2]];
   // (void *)objc_msgSend(self, @selector(move:),[NSNumber numberWithInt:3]);
    void (*objc_msgSendTyped)(id self, SEL _cmd, id obj) = (void *)objc_msgSend;
    objc_msgSendTyped(self,@selector(move:),[NSNumber numberWithInt:3]);
    return 100*factor;
    //objc_msg
}


@end
由于版本的提升,对于objc_msgSend必须用一个函数指针来取。

测试代码

    Class clazz=NSClassFromString(@"LWBCar2");
        id car=[[clazz alloc]init];
        [car performSelector:@selector(addSpeed:) withObject: [NSNumber numberWithDouble:3.4]];

利用反射技术来生成对象,并动态调用方法。结果:

2017-04-11 20:13:15.504 Prj4[1279:1626027] 汽车正在路上走~~0
2017-04-11 20:13:15.506 Prj4[1279:1626027] 汽车正在路上走~~1
2017-04-11 20:13:15.506 Prj4[1279:1626027] 汽车正在路上走~~0
2017-04-11 20:13:15.506 Prj4[1279:1626027] 汽车正在路上走~~1
2017-04-11 20:13:15.506 Prj4[1279:1626027] 汽车正在路上走~~0
2017-04-11 20:13:15.506 Prj4[1279:1626027] 汽车正在路上走~~1
2017-04-11 20:13:15.507 Prj4[1279:1626027] 汽车正在路上走~~2
Program ended with exit code: 0




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值