OC做為一門面向?qū)ο笳Z言贺辰,自然具有面向?qū)ο蟮恼Z言特性户盯,如封裝、繼承饲化、多態(tài)莽鸭。他具有靜態(tài)語言的特性(如C++),又有動(dòng)態(tài)語言的效率(動(dòng)態(tài)綁定吃靠、動(dòng)態(tài)加載等)硫眨。整體來說,確實(shí)是一門不錯(cuò)的編程語言巢块。
現(xiàn)在礁阁,讓我來想想OC的動(dòng)態(tài)語言特性巧号。OC的動(dòng)態(tài)特性表現(xiàn)為了三個(gè)方面:動(dòng)態(tài)類型、動(dòng)態(tài)綁定姥闭、動(dòng)態(tài)加載丹鸿。之所以叫做動(dòng)態(tài),是因?yàn)楸仨毜竭\(yùn)行時(shí)(run time)才會(huì)做一些事情棚品。
一靠欢、Objective-C多態(tài)
1.概念:相同接口,不同的實(shí)現(xiàn)
來自不同類可以定義共享相同名稱的方法铜跑。
動(dòng)態(tài)類型(id)能使程序直到執(zhí)行時(shí)才確定對(duì)象所屬類型
動(dòng)態(tài)類型綁定能使程序直到執(zhí)行時(shí)才確定要對(duì)對(duì)象調(diào)用的實(shí)際方法
2.Objective-C不同于傳統(tǒng)程序設(shè)計(jì)語言门怪,它可以再運(yùn)行時(shí)加入新的數(shù)據(jù)類型和新的程序模塊:動(dòng)態(tài)類型識(shí)別,動(dòng)態(tài)綁定疼进,動(dòng)態(tài)加載
3.id類型:通用指針類型薪缆,弱類型,編譯時(shí)不進(jìn)行類型檢查
二伞广、動(dòng)態(tài)類型識(shí)別
1.任意NSObject的子類都會(huì)繼承NSObject的isa實(shí)例變量,而且當(dāng)NSObject的子類實(shí)例化對(duì)象時(shí)疼电,isa實(shí)例變量永遠(yuǎn)是對(duì)象的第一個(gè)實(shí)例變量嚼锄。
2.類對(duì)象
*類對(duì)象再程序運(yùn)行時(shí)一直存在。
*類對(duì)象是一種數(shù)據(jù)結(jié)構(gòu)蔽豺,存儲(chǔ)類的基本信息:類大小区丑,類名稱,類的版本以及消息與函數(shù)的映射表等
*類對(duì)象所保存的信息在程序編譯時(shí)確定修陡,在程序啟動(dòng)時(shí)加載到內(nèi)存中沧侥。
*類對(duì)象代表類,class代表類對(duì)象魄鸦,類方法屬于類對(duì)象
*如果消息的接收者是類名宴杀,則類名代表類對(duì)象
*運(yùn)行時(shí),所有類的實(shí)例都由類對(duì)象生成拾因,類對(duì)象會(huì)把實(shí)例的isa的值修改成自己的地址旺罢,每個(gè)實(shí)例的isa都指向該實(shí)例的類對(duì)象,*從類對(duì)象里可以知道父類信息绢记、可以響應(yīng)的方法等
*類對(duì)象只能使用類方法扁达,不能用實(shí)例方法
3.SEL類型
Objective-C在編譯的時(shí)候,會(huì)根據(jù)方法的名字 (包括參數(shù)序列),生成一個(gè)用來區(qū)分這個(gè)方法的唯一的一個(gè)標(biāo)示(ID),這個(gè)標(biāo)示(ID)就是SEL類型的,在運(yùn)行時(shí)候是通過方法的標(biāo)示來查找方法的。只要方法的名字(包括參數(shù)序列)相同,那么它們的 ID都是相同的蠢熄」蚪猓可以通過@select()指示符獲得方法的標(biāo)示。SEL mydraw =@select(draw)签孔;
NSSelectorFromString(NSString);根據(jù)方法名得到方法標(biāo)識(shí)
(NSString)NSStringFromSelector(SEL);得到SEL類型的方法名
4.動(dòng)態(tài)類型識(shí)別常用方法
-(BOOL)isKindOfClass:classObj 是否是classObj類或其子類
-(BOOL)isMemberOfClass:classObj是否是classObj的實(shí)例
-(BOOL)respondsTosSelector:selector 類中是否有這個(gè)方法
NSClassFromString(NSString*);由字符串得到類對(duì)象
NSStringFromClass([類名 Class]);由類名得到字符串
Class rectClass= [Rectangle class];通過類名得到類對(duì)象
Class aClass =[anObject class];通過實(shí)例得到類對(duì)象
if([obj1 class]== [obj2 class])判斷是不是相同類的實(shí)例
- 可以將對(duì)象分為id類型和靜態(tài)類型
- 如果不涉及到多態(tài),盡量使用靜態(tài)類型
– 靜態(tài)類型可更好的在編譯階段而不是運(yùn)行階段指 出錯(cuò)誤
– 靜態(tài)類型能夠提高程序的可讀性
三叉讥、動(dòng)態(tài)綁定
- 在objective-c中,一個(gè)對(duì)象內(nèi)否調(diào)用指定的方法不是由編譯器決定而是由運(yùn)行時(shí)決定,這被稱作是方法的動(dòng)態(tài)綁定砾跃。
- 在objective-c里,對(duì)象不調(diào)用方法,而是接收消息,消息 表達(dá)式為: [reciver message];運(yùn)行時(shí)系統(tǒng)首先確定接收者的類型(動(dòng)態(tài)類型識(shí)別),然 后根據(jù)消息名在類的方法列表里選擇相依的方法執(zhí)行,所 以在源代碼里消息也稱為選擇器(selector)
- 消息函數(shù)的作用:
– 首先通過第一個(gè)參數(shù)的receiver,找到它的isa 指針,然 后在isa 指向的Class 對(duì)象中使用第二個(gè)參數(shù)selector 查 找方法;
– 如果沒有找到,就使用當(dāng)前Class 對(duì)象中的新的isa 指針 到上一級(jí)的父類的Class 對(duì)象中查找;
– 當(dāng)找到方法后,再依據(jù)receiver 的中的self 指針找到當(dāng)前 的對(duì)象,調(diào)用當(dāng)前對(duì)象的具體實(shí)現(xiàn)的方法(IMP),然后傳 遞參數(shù),調(diào)用實(shí)現(xiàn)方法。
– 假如一直找到NSObject 的Class 對(duì)象,也沒有找到你調(diào) 用的方法,就會(huì)報(bào)告不能識(shí)別發(fā)送消息的錯(cuò)誤节吮。 - Objetive-C中的Method結(jié)構(gòu)
struct objc_method{
SEL method_name;//方法名
char *method_types; //方法地址
IMP method_imp; //方法地址(IMP)
};
typedefobjc_method Method; - 什么是IMP
– IMP是”implementation”的縮寫,它是objetive-C 方法 (method)實(shí)現(xiàn)代碼塊的地址,類似函數(shù)指針,通過它可以 直接訪問任意一個(gè)方法抽高。免去發(fā)送消息的代價(jià)。 - 獲取方法的IMP
– -(IMP)methodForSelector:(SEL)aSelector;
SEL print_sel =NSSelectorFromString(@“print:”);//獲得SEL IMP imp=[person methodForSelector:print_sel];//得到IMP imp(person,print_sel,@“*********”);//通過IMP直接調(diào)用方法 等效調(diào)用:[person print_sel:@“*********”];
– imp的第一參數(shù)是對(duì)象自己(self),第二參數(shù)是方法標(biāo)示, 第三個(gè)是方法的參數(shù)
四透绩、動(dòng)態(tài)加載:運(yùn)行時(shí)加載新類
在運(yùn)行時(shí)創(chuàng)建一個(gè)新類,只需要3步:
1 類中每一個(gè)方法在內(nèi)部轉(zhuǎn)換后的結(jié)構(gòu)體
struct objc_method
{
SEL method_name; 函數(shù)名稱
char *method_types; 函數(shù)類型
IMP method_imp; 函數(shù)的具體實(shí)現(xiàn) 這里是一個(gè)指針翘骂,指向具體的實(shí)現(xiàn)
};
2 每一個(gè)類擁有的的函數(shù)列表
struct objc_method_list
{ struct objc_method_list *obsolete; 函數(shù)列表
int method_count; 類中函數(shù)的個(gè)數(shù)
struct objc_method method_list[1]; 函數(shù)列表中的第一個(gè)函數(shù)地址};
下面是函數(shù)具體的加載過程0. 定義一個(gè)函數(shù)
- 創(chuàng)建一個(gè)上面所說的objc_method結(jié)構(gòu)體的實(shí)例,顯然這個(gè)結(jié)構(gòu)體的實(shí)例是一個(gè)函數(shù)帚豪,內(nèi)部的參數(shù)由步驟0決定
1.0 為結(jié)構(gòu)體的函數(shù)名method_name賦值碳竟;
1.1 為結(jié)構(gòu)體的函數(shù)實(shí)現(xiàn)賦值。(函數(shù)指針指向(內(nèi)存代碼區(qū))具體的實(shí)現(xiàn))狸臣。 - 添加objc_method結(jié)構(gòu)體的實(shí)例到上面多說的第二個(gè)結(jié)構(gòu)體 objc_method_list中
- 調(diào)用class_addMethods方法莹桅,將objc_method_list添加到相應(yīng)的類里面
下面代碼示例:
import <objc/objc-class.h>
// create a class with no methods
@interface EmptyClass : NSObject { }
@end
@implementation EmptyClass
@end
// define the function to add as a method
id sayHello ( id self, SEL _cmd,... )
{
NSLog (@"Hello");
}
void addMethod ()
{
struct objc_method myMethod; <span style="white-space:pre"> </span>//0 創(chuàng)建method實(shí)例
myMethod.method_name = sel_registerName("sayHello"); <span style="white-space:pre"> </span>//1.0 為函數(shù)名賦值
myMethod.method_imp = sayHello; <span style="white-space:pre"> </span>//1.1 為函數(shù)實(shí)現(xiàn)賦值
struct objc_method_list * myMethodList;
myMethodList = malloc (sizeof(struct objc_method_list));
myMethodList->method_count = 1;
myMethodList->method_list[0] = myMethod;<span style="white-space:pre"> </span>//2 將自定義的函數(shù)實(shí)例添加到 list中
class_addMethods ( [EmptyClass class], myMethodList );//3 將list綁定到類上面
// 調(diào)用
EmptyClass * instance = [[EmptyClass alloc] init];
[instance sayHello];
[instance release];
}
這基本就是OC動(dòng)態(tài)加載的過程。