2. objC 动态绑定(dynamic binding)

来源:互联网 发布:sep软件 编辑:程序博客网 时间:2024/06/11 08:58

1 动态绑定理解

       动态绑定,在编译期间,不能决定当前调用函数的地址;在程序运行时,通过当前对象的类型来判断当前调用函数的地址所在。这一点和C和C++不同,在C中,所有函数的调用都是在编译过程中所决定的。在C++中,只有virtual函数的调用是通过v-table在运行时进行查找的,其他都是静态调用。

      动态调用速度慢,静态调用速度快。

2 动态绑定原理

2.1 SEL

     SEL 是objc_selector结构的指针,objc_selector的结构如下

     objc_selector 的GNU Objective-C的实现

typedefconststructobjc_selector{  void *sel_id;  constchar *sel_types;} *SEL

     objc_selector 的NeXT Objective-C的实现

     没有查到相关的文档,在相关文章中,其实现直接就是一个字符串。从此函数也可以知道

      NSLog(@"%s",@selector(say: usingLag:);将打印出say:usingLag:。说明@selector只是简单的翻译,不判断say:usingLag:函数是否被某个类定义过。

2.2 IMP

     IMP是一个obj-c中,内部定义的函数指针:

/*** Definition of method type. When retrieving the implementation of a** method, this is type of the pointer returned*/typedefid (*IMP)(id, SEL


     向Child的对象pChild发送say:(int) LagType的消息,[pChild say:0]。编译器会将上边的代码翻译为id objc_msgSend(pChild, @selector(say:), LagType);其中,此函数申明为id objc_msgSend(id theReceiver, SEL theSelector, ...),此函数将在theReceiver中isa所指向的类对象的objc_method_list方法列表中去查找SEL所对应的IMP函数地址,进而进行执行。

    /**  Method Template */    typedef struct objc_method *Method;    struct objc_method {        SELmethod_name;        char *method_types;        IMPmethod_imp;    };    struct objc_method_list {        struct objc_method_list *obsolete;        int method_count;#ifdef __alpha__                int space;#endif            struct objc_methodmethod_list[1];  /* variable length structure */    };

2.3 性能

       显然,这种函数的调用的方法,显然要比静态绑定要慢的多。于是,在程序中,我们常常可以把函数的地址先记录下来,然后直接进行调用。如下边的代码,但是,通过我们实际测速,这两种方式,基本上相差很少,是由于在Class中还有一个方法地址的Cache,会大大加快函数调用方法。所以,在实际的调用过程中,objC的函数调用没有象想象中的那么慢。

例如:

patient.h文件@interface Person : NSObject{@privateNSMutableString* name;@privateNSMutableString* uid;@privateNSDate* birthday;@privateNSString* sex;}@property(nonatomic, retain) NSMutableString* name;@property(nonatomic, retain) NSMutableString* uid;@property(nonatomic, retain) NSDate* birthday;@property(nonatomic, retain) NSString* sex;/** */-(id) init:(NSMutableString*) persionId andBirthDay:(NSDate*) birth;-(void) printOut;@end/**the below is about the Patient */@interface Patient: Person{@privateNSMutableString* medical_insure_card_id;}@property(nonatomic, retain) NSMutableString* medical_insure_card_id;-(id) init:(NSMutableString*) personId andBirthDay:(NSDate *)birth andMedicalInsureCardId:(NSMutableString*) cardId;-(void) printOut;@end/***/@interface PaitentCreator:NSObject+(Patient*) CreatePatient;@endpatient.m文件@implementation Person@synthesize name;@synthesize uid;@synthesize birthday;@synthesize sex;-(id) init:(NSMutableString*) persionId andBirthDay:(NSDate*) birth{    id temp = [superinit];    if (!temp || self != temp)    {        returnnil;    }    self.uid = persionId;    self.birthday = birth;    returnself;}-(void) printOut{    //NSLog(@"the person name is %@ uid = %@ birthday = %@",self.name,self.uid,[self.birthday description] );    NSLog(@"the person name is %@ ",self.name);}-(void)dealloc{    if (uid != nil) {        [uidrelease];        uid = nil;        NSLog(@"uid release");    }    if (birthday != nil) {        [birthdayrelease];        birthday = nil;        NSLog(@"birthday release");    }    if (sex != nil) {        [sexrelease];        sex = nil;        NSLog(@"sex release");    }    if(name != nil)    {        [namerelease];        name = nil;        NSLog(@"name release");    }    [superdealloc];}@end@implementation Patient@synthesize medical_insure_card_id;-(id) init:(NSMutableString*) personId andBirthDay:(NSDate *)birth andMedicalInsureCardId:(NSMutableString*) cardId{    id temp = [superinit:personId andBirthDay:birth];    if (!temp || self != temp) {        returnnil;    }    self.medical_insure_card_id = cardId;    returnself;}-(void) printOut{    [superprintOut];    //NSLog(@"the patient medical card id = %@",self.medical_insure_card_id);}-(void) dealloc{    if(medical_insure_card_id != nil)    {        [medical_insure_card_idrelease];        medical_insure_card_id = nil;    }    [superdealloc];}@end@implementation PaitentCreator+(Patient*) CreatePatient{    Patient* pTempPatient = [[Patientalloc] init];    [pTempPatient autorelease];    return pTempPatient;}@end main.mtypedef void (*PrintInformation)(id, SEL);        Patient* patient = [[Patientalloc] init:[[NSMutableStringalloc] initWithString:@"12345678"] andBirthDay: [NSDatedate] andMedicalInsureCardId:[[NSMutableStringalloc] initWithString:@"bj_jst_2012.1.21_beijing_china"]];        patient.name = [[NSMutableStringalloc] initWithString:@"Zhao^QiaoZhuan^^^"];                    PrintInformation printFun = nil;        printFun = (PrintInformation)[patient methodForSelector:@selector(printOut)];                for (int i = 0; i < 10000; ++i) {            printFun(patient,@selector(printOut));        }//12286 - 7643 = 4643ms        NSLog(@"------------------------------------------------------------------");        NSLog(@"------------------------------------------------------------------");        NSLog(@"------------------------------------------------------------------");        for (int i = 0; i < 10000; ++i) {            [patient printOut];        }//16988 - 12287 = 4701ms

        回想,在第一节中dynamic typing的讲解,知道performSelector等函数是和动态绑定中,查找函数有关系的。