iOS开发笔记(4)---- 反射

来源:互联网 发布:下象棋软件 编辑:程序博客网 时间:2024/04/29 05:48

反射的强大之处在于,我们可以将对象与依赖对象之间完全解耦,创建对象可以不引用头文件,操作属性、方法可以不依赖于对象,操作对象可以不依赖于类型,操作类型可以不依赖于引用等等等等。最直观的效果是,即使不引用头文件亦可操作类型、对象及对应属性与方法。
借助强大的runtime特性,在iOS平台上我们也得以实现反射。

//使用前需要先引用runtime头文件#import <objc/runtime.h>

在这里,我们创建一个示例类型IPZClassOne 并声明四个有代表性的方法。

@interface IPZClassOne : NSObject+ (void) classMethod;              //类型方法+ (IPZClassOne*) getSingleLeton;   //单例- (void) instanceMethod;           //实例方法- (void) onFinshedHandler:(NSString *) completeHandler;//含参数方法@end

类型反射

获取类型分为两种,通过对象获取和通过类型名称获取。

  • 通过对象获取: Class class = [self class];
  • 通过名称获取: Class class=NSClassFromString(@"IPZClassOne");

这里需要注意的是,如果名称错误或者该类型不存在的话也会有可能类型反射失败。

类型获取成功时如下图:
类型获取成功
类型获取失败时如下图:
类型获取失败

类型是一种特殊的对象,从图中可以看出党获取类型失败时类型对象地址为0x0,因此我们可以通过该对象的地址来判断是否获取成功。

if(class==0x0){     NSLog(@"Class Unfound"); } 

实例化对象

在iOS中实例化对象的方法同样有两种:单例或者init方法。

  • init方法实例化对象
    id instance=[[class alloc] init];
  • 单例方法实例化对象
SEL classSelector=NSSelectorFromString(@"getSingleLeton");//classSelector=@selector(getSingleLeton);if ([class respondsToSelector:classSelector]) {    id instance= [class performSelector:classSelector];}

单例实现中上面这种调用selector的方法是比较安全的方法,在此之外还有一种直接调用的方法,即:id instance=[class getSingleLeton];
然而直接使用的话编译器会报未找到该方法: No known class method for selector ‘getSingleLeton’,此种情况只需声明或定义一个同名称空方法即可

通过反射到的类型实例化对象同样有失败的可能,判断成功或失败的方法同上。

方法调用

上面已经讲了单例亦即类型方法的调用,实例对象的调用方法与之相同。

SEL  instanceSelector=NSSelectorFromString(@"instanceMethod");instanceSelector=@selector(instanceMethod);if ([instance respondsToSelector:instanceSelector]) {    [instance performSelector:instanceSelector];}以及: [instance instanceMethod];

然而,performSelector这种方式只能调用无参方法,有参方法仍需直接调用。

在直接调用方法之前,我们可以声明一个协议。

@protocol IPZCLassOne@optional+(void) classMethod;+(id) getSingleLeton; //返回值为id-(void) instanceMethod;-(void) onFinshedHandler:(id) completeHandler;//参数声明为id@end

此外,我们还可以通过反射在运行时获取实例方法列表及其内容。(类型方法列表无法获取,只能根据名称获取单个方法)
获取实例方法:

u_int count;Method* methods=class_copyMethodList(class, &count);//获取所有实例方法for (int i = 0; i < count ; i++){    SEL instanceSelector=method_getName(methods[i]);//获取实例方法selector    const char* methodName =sel_getName(instanceSelector);//获取方法名,类似还有获取方法实现等 } free(methods);

属性获取

u_int count;objc_property_t* properties = class_copyPropertyList(class, &count);//获取属性列表NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count];for (int i = 0; i < count ; i++){    const char* propertyName = property_getName(properties[i]);//获取属性名称    [propertyArray addObject:[NSString  stringWithCString:propertyName encoding:NSUTF8StringEncoding]];}free(properties);for (NSString *name in propertyArray){    NSString* value = [self valueForKey:name];//获取属性值}

0 0