Object C学习笔记17-动态判断和选择器

  当时学习Object C的时被人鄙视了一顿,说使用.NET的思想来学Object C就是狗屎;不过也挺感谢这位仁兄的,这让我学习的时候更加的谨慎。今天的学习笔记主要记录Object C中的动态类型相关内容。html

  首先仍是和.NET先对比一下,.NET中存在一个关键字var ,这个估计用过.NET的都知道,除非没有接触过3.0以上版本的。在.NET中可以使用var来声明任何类型的局部变量,负责告诉编译器,该变量须要根据初始化表达式来推断变量的类型,并且只能是局部变量.可是这里要注意的时var 并非一个新的类型,只是一个关键字而已,在定义参数和返回值的时候都不能使用var.ide

  在.net中还有一个类型dynamic,表示变量的类型在运行时决定,也就是在运行此代码的时候才去校验类型是否符合等,若是类型不符则会抛出异常。而var则会在编译的过程就可以发现类型是否准确。学习

  在这里咱们要说Object C中的id类型 和 var 以及 dynamic 有什么区别?测试

 

  一. Object C中的id类型atom

    在Objective-C 中,id 类型是一个独特的数据类型。在概念上能够转换为任何数据类型。换句话说,id 类型的变量能够存听任何数据类型的对象。在内部处理上,这种类型被定义为指向对象的指针,其实是一个指向这种对象的实例变量的指针。spa

    先看一段代码了解一下id类型的时候:.net

id stu=[[Student alloc] init];
[stu eat];
        
id per=[[Person alloc] init];
[per eat];

    以上代码分别用建立了两个类Student 和 Person的实例,类型都是使用的id,而且调用了其相应的方法,成功运行。指针

 

  二. 动态判断code

    在Object C中如何判断某个类实例是不是某个类的子类,某个类中是否包含某个方法。这个要求彷佛和.NET中的反射有点相似,的确在Object中一样提供了相似的方法来动态判断。orm

    咱们先定义一个父类:

#import <Foundation/Foundation.h>

@interface Person : NSObject{
    NSString *name;
    int age;
    NSString *address;
}
@property (nonatomic,retain) NSString *name;
@property (nonatomic,assign) int age;
@property (nonatomic,retain) NSString *address;

-(void) eat;

-(void) speak;

-(void) write;

-(Person *) getPerson;

-(id) getString;

+(void) Info;

@end

----------------------------------------------------------------
#import "Person.h"

@implementation Person

@synthesize name;
@synthesize age;
@synthesize address;

-(void) eat{
    NSLog(@"Person.eat()");
}

-(void) speak{
    NSLog(@"Person.speak()");
}

-(void) write{
    NSLog(@"Person.write()");
}

-(Person *) getPerson{
    Person *p=[[Person alloc] init];
    p.name=@"li";
    p.age=25;
    p.address=@"上海";
    return p;
}

-(id) getString{
    Person *p=[[Person alloc] init];
    p.name=@"lin";
    p.age=22;
    p.address=@"北京";
    return p;
}

+(void) Info{
    NSLog(@"Person.Info");
}

@end
Person 类

    而后定义一个子类,用于继承Person类。

#import "Student.h"

@implementation Student

@end
Student 类

    Student类继承了Person类,说明Student类拥有了Person类的全部方法和属性

    (1) isMemberOfClass 用于判断是不是某个类的实例

bool flag1=[stu isMemberOfClass:[Student class]];
NSLog(@"%d",flag1);
bool flag2=[stu isMemberOfClass:[Person class]];
NSLog(@"%d",flag2);

    上面的代码 flag1 为yes,而flag2为no,说明stu是Student类的实例,Student为Person的子类,可是不能判断为Person的实例。

    (2) isKindOfClass 判断是否为某个类的实例或者某个类子类的实例

bool flag1=[stu isKindOfClass:[Student class]];
NSLog(@"%d",flag1);
bool flag2=[stu isKindOfClass:[Person class]];
NSLog(@"%d",flag2);

    由于Student是Person的子类,因此上面flag1,flag2 的都为YES

    (3) respondsToSelector 用于判断某个类型或者对象是否有能力回应(调用)指定的方法

bool flag3=[per respondsToSelector:@selector(eat)];
        NSLog(@"%d",flag3);
        
        bool flag4=[stu respondsToSelector:@selector(eat)];
        NSLog(@"%d",flag4);
        
        bool flag5=[per respondsToSelector:@selector(Info)];
        NSLog(@"%d",flag5);
        
        bool flag6=[Person respondsToSelector:@selector(Info)];
        NSLog(@"%d",flag6);
respondsToSelector 测试代码

    上面的代码测试输出结果以下:

2014-03-22 20:28:09.778 ObjectSelect[11321:303] 1
2014-03-22 20:28:09.778 ObjectSelect[11321:303] 1
2014-03-22 20:28:09.778 ObjectSelect[11321:303] 0
2014-03-22 20:28:09.779 ObjectSelect[11321:303] 1

    第一个和第二个方法的调用都返回1,说明其有能力回应(调用)方法eat, 关键看第三个和第四个方法的调用,返回0,1 说明实例和对象的调用是不同的,而Info方法是一个全局方法 ,用 "+" 标识的方法就是全局方法,至关于静态方法。第3个方法是使用实例来调用的返回0,说明对象实例是没有能力调用静态方法的。

     (4) instancesRespondToSelector 用于判断某个对象的实例是否有能力回应(调用)指定的方法

        bool flag7=[Person instancesRespondToSelector:@selector(eat)];
        NSLog(@"%d",flag7);
        bool flag8=[Person instancesRespondToSelector:@selector(Info)];
        NSLog(@"%d",flag8);

    上面的测试代码输出结果以下:

2014-03-22 20:39:04.700 ObjectSelect[11344:303] 1
2014-03-22 20:39:04.700 ObjectSelect[11344:303] 0

    第一个方法调用返回1,说明Person的实例能够调用eat方法,第二个方法返回0,说明Person的实例不能够调用Info方法。

 

  三. 如何动态调用方法

    上面已经说到了,任何一个对象的实例咱们均可以使用id来指向其地址,这是一个动态的类型那么如何调用其具体的方法。

[stu performSelector:@selector(eat)];
[Person performSelector:@selector(Info)];

    使用performSelector 方法能够动态的调用其方法,若是是实例方法则调用的须要使用对象实例,而调用静态方法这须要使用对象自己。

    上面的办法调用都是没有参数的,那么如何调用有输入参数的方法呢?

[stu performSelector:@selector(speak:) withObject:@"ddddd"];
        
[stu performSelector:@selector(write:andAge:) withObject:@"fasdfadaf" withObject:@"333"];

    使用withObject 来填充参数.可是这个方法的调用有点不足的地方,若是有多个参数输入参数就有问题。 这个地方尚未彻底没有弄清楚,有待后续研究。若是真的涉及到多个参数,那么可使用对象封装好这些参数或者将参数存入一个集合中传递输入。

 

  四. 总结

    这篇主要讲到了动态类型id,以及其如何使用。还有关于类的动态判断以及选择器。但都只是比较粗略的介绍了,后面的学习中继续深刻研究。

    本文开头的时候对比了.NET 中的var , dynamic 。 从上面的文章介绍,那么Object C中的id 和 .NET中的哪一个关键字比较像,我的的学习体会和dynamic比较相似,若有不对的正确的地方请高手斧正!

 

  补充说明文章: Object C学习笔记18-SEL,@ selector,Class,@class

  本文到此结束,请高手勿喷,菜鸟的学习须要鼓励!

相关文章
相关标签/搜索