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