天天看點

objective C中的@class, SEL , IMP等靈活機制(五)

holydancer原創,如需轉載,請在顯要位置注明:

轉自holydancer的CSDN專欄,原文位址:http://blog.csdn.net/holydancer/article/details/7347399

在objective c中,如果細心的話會發現,每個類中都會自動生成一個class 類型的isa,

@interface NSObject <NSObject> {
     Class    isa;
 }
           

isa是什麼,class又是什麼呢,找到Class的定義我們會發現如下:

typedefstruct objc_class *Class;
           

而objc_class以前的定義又如下,現在據說被封閉了,不知道有沒有再作修改,總之友善我們了解就好:

struct objc_class {
     Class isa;
     
     Class super_class;
     
     const char *name;
     
     long version;
     long info;
     
     long instance_size;
     struct objc_ivar_list *ivars;
     struct objc_method_list **methodLists; 
     
     struct objc_cache *cache;
     struct objc_protocol_list *protocols;   
 }
           

于是我們就有了點頭緒了,isa,is a pointer,是個指針(根據網上的資料,這樣了解是最貼近事實的,不管你們信不信,反正我是信了),每個類都有一個class類型的指針isa,繼承自NSObject中,繼承關系,方法變量等資訊都存放在isa中,isa作為一個隐藏的屬性,會自動生成于每個類之中。有了這個前提,也就可以解釋為什麼我們可以根據@class來代替任意一個類了,看代碼:

Human.h

#import <Foundation/Foundation.h>

@interface Human : NSObject
-(void)say;
@end
           

Human.m

#import "Human.h"

@implementation Human
-(void)say
{
    NSLog(@"Human中的say方法");
}
@end
           

main.h

#import <Foundation/Foundation.h>
#import "Human.h"
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Class c =NSClassFromString(@"Human");
        [[c new] say];
        //以上CLASS類型的c,就相當于Human類。
    }
    return 0;
}
           

class可以靈活的代替别的類,SEL與其類似,不同的是SEL代替的是方法,可以友善的代替其他方法,class中是因為有isa屬性儲存有類的資訊,而SEL是因為即使是在不同的類中,方法名隻要相同,這兩個方法的ID就相同,SEL就是根據這個ID來找到該方法,再根據調用該方法的類的不同來找到唯一的位址。看代碼再作解釋:

#import <Foundation/Foundation.h>


#import <Foundation/Foundation.h>

@interface Human : NSObject
-(void)say;
@end
@implementation Human
-(void)say
{
    NSLog(@"Human中的say方法");
}
@end
//上面定義了一個human類,裡面有一個say方法
@interface man:NSObject
{}
-(void)say; @end

@implementation man
-(void)say
{
    NSLog(@"man中的say方法");
}
@end

//在上面定義了一個man類,同樣有一個say方法
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Class a =NSClassFromString(@"Human");
        Class b =NSClassFromString(@"man");
        //根據方法名say找到該方法的id,将sel與其綁定;
        SEL sel = NSSelectorFromString(@"say");
        [[a new] performSelector:sel];
        [[b new] performSelector:sel];
        
        
        
    }
    return 0;
}
           

結果如下:

2012-03-13 10:13:24.900 String[2725:403] Human中的say方法
2012-03-13 10:13:24.901 String[2725:403] man中的say方法
           

通過以上代碼我們會發現,SEL通過方法名綁定後,可以被多個類執行個體調用,找了些網上的資料,解釋都是說方法名一樣的話,ID會一樣,位址仍不同,才會實作這樣的效果,我們不談論是否準确,但我個人認為這是目前最合理的解釋。這種用法的優勢一方面是靈活性更高,類似于多态,另一方面是,這種用法sel找方法時比對的是ID而不是字元串方法名,是以在效率上會高一些。還有一種更終極的方法,直接對應方法的位址,這種方法效率最高,請看代碼:

#import <Foundation/Foundation.h>


#import <Foundation/Foundation.h>

@interface Human : NSObject
-(void)say;
@end
@implementation Human
-(void)say
{
    NSLog(@"Human中的say方法");
}
@end
//上面定義了一個human類,裡面有一個say方法
@interface man:NSObject
{}
-(void)say; @end

@implementation man
-(void)say
{
    NSLog(@"man中的say方法");
}
@end

//在上面定義了一個man類,同樣有一個say方法
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        Human *human =[Human new];
        man *ma=[man new];
        //根據方法名say找到該方法的id,将sel與其綁定;
        SEL sel [email protected](say);//也可以這樣寫:SEL sel=NSSelectorFromString(@"say");
        IMP imp1 = [human methodForSelector:sel];     
        IMP imp2 = [ma methodForSelector:sel];     

        imp1(human,sel);
        imp2(ma,sel);
        //因為每個方法都有自己的位址,這種方式直接找到位址區分相同ID的方法,效率最高,但靈活性不如SEL方式。
        
    }
    return 0;
}
           

輸出語句:

2012-03-13 10:35:21.446 String[3763:403] Human中的say方法
2012-03-13 10:35:21.450 String[3763:403] man中的say方法
           

今天這些内容不太好了解,我用自己了解的方式給大家再解釋一遍,class用于代替類,增加靈活性,因為我們不知道什麼時候會用到什麼類,方法也是如此,是以SEL可以代替方法,每個方法有方法名,ID,位址,相同的方法名,ID也一樣,正常情況下我們根據方法名找到方法,用SEL方法可以根據ID找到方法,而用IMP方式可以直接找到位址,但是靈活性不如SEL方法,雖然效率最高。好了,今天到此為止。

關鍵字:objective-c ,objective c , oc ,@class, SEL ,selector ,IMP