2. objC 动态绑定(dynamic binding)

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;
@end
patient.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.m
typedef 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等函数是和动态绑定中,查找函数有关系的。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值