解析Objective-C反射
Objective-C反射是本文要介紹的內(nèi)容,我第一次接觸Java的時(shí)候就覺(jué)得整個(gè)反射包都很新穎,它使得Java和解釋型的腳本語(yǔ)言更接近了,與此同時(shí)也拉開(kāi)了和主流的C和C++的距離。
在運(yùn)行時(shí)可以窺視到一個(gè)對(duì)象的類(lèi)元數(shù)據(jù)真的很不可思議,盡管這些可能不會(huì)在日常應(yīng)用編程中經(jīng)常使用到。從Java轉(zhuǎn)到Objective-C的程序員應(yīng)該會(huì)樂(lè)見(jiàn)Objective-C也支持反射。實(shí)際上,Objective-C有很多諸如動(dòng)態(tài)改變類(lèi)定義以及創(chuàng)建一個(gè)新類(lèi)的動(dòng)態(tài)特征。
不過(guò)很難說(shuō)這些功能有多大的作用,這也讓我覺(jué)得Objective-C是一個(gè)有些臃腫的語(yǔ)言。在我看來(lái),Objective-C有一個(gè)定位危機(jī):它是解釋型語(yǔ)言還是編譯語(yǔ)言?運(yùn)行時(shí)很大程度上是動(dòng)態(tài)的。和C++不同,Objective-C是運(yùn)行時(shí)綁定的。這也是為什么我們可以在實(shí)現(xiàn)時(shí)定義一個(gè)從來(lái)沒(méi)有在頭文件中聲明的方法,或者通過(guò)Category擴(kuò)展類(lèi)。不幸的是由于這種臃腫使得找到一些日常編程中有用的東西變得困難,本文就是要去發(fā)現(xiàn)其中的一些“寶藏”。
根類(lèi)NSObject
大部分(如果不是全部的話)的動(dòng)態(tài)反射支持來(lái)自NSObject 類(lèi)。和Java的Object對(duì)象類(lèi)似,NSObject是所有類(lèi)(除了一些很少見(jiàn)的例外)的根類(lèi)。所以所有你寫(xiě)的類(lèi)應(yīng)該都可以支持反射。需要指出的所有這些的反射支持并不是Objective-C語(yǔ)言的一部分,而是源于NS*的運(yùn)行時(shí)環(huán)境。這也是為什么這些東西感覺(jué)被加入一些額外東東的原因。因?yàn)樗褪潜患尤肓祟~外東東。
獲取類(lèi)的元數(shù)據(jù) 通過(guò)調(diào)用如下的類(lèi)方法你就可以獲取到一個(gè)對(duì)象的類(lèi)的元數(shù)據(jù):
- Class c = [self class];
該方法既是實(shí)例方法也是類(lèi)方法。它返回一個(gè)帶有很多神奇信息的C構(gòu)造體,比如實(shí)例變量、方法等等。所有這些和java.lang.reflect包相比都有些過(guò)時(shí)了,利用Objective-C訪問(wèn)這些信息的接口看起來(lái)很復(fù)雜。這可能就是故意設(shè)計(jì)成這樣來(lái)“過(guò)濾”一些不合格的程序員。目前為止我唯一使用這些的地方就是為下面將要介紹的isKindOfClass:方法提供參數(shù)。一直以來(lái)我都不需要去窺視類(lèi)結(jié)構(gòu)的內(nèi)容。
動(dòng)態(tài)方程調(diào)用我已經(jīng)在方法調(diào)用一文中介紹了反射的一個(gè)方面。這使得你可以在運(yùn)行時(shí)創(chuàng)建一個(gè)方法調(diào)用并傳入?yún)?shù)。這和Java中使用java.lang.reflect.Method類(lèi)很相似。
檢查繼承關(guān)系
Java有一個(gè)名為instanceof的操作符可以用來(lái)檢查一個(gè)對(duì)象是否是一個(gè)特定類(lèi)或者接口的實(shí)例。 Objective-C也有類(lèi)似的功能,就是通過(guò)isKindOfClass:方法。isKindOfClass:會(huì)在消息接收者是指定類(lèi)及其子類(lèi)的實(shí)例的情況下返回YES。比如有一個(gè)關(guān)聯(lián)的指針數(shù)組,這樣就可以根據(jù)其類(lèi)型進(jìn)行不同的操作:
- for(BaseClass* base in myArray) {
- if([base isKindOfClass:[ClassOne class]]) {
- // do stuff specific to ClassOne
- } else if([base isKindOfClass:[ClassTwo class]]) {
- // do stuff specific to ClassTwo
- } else if([base isKindOfClass:[ClassThree class]]) {
- // do stuff specific to ClassThree }
- // etc }
如果你需要一個(gè)精確的類(lèi)匹配,而不是匹配任何繼承類(lèi),你就可以使用isMemberOfClass:方法。
檢查是否符合協(xié)議 和實(shí)例檢查類(lèi)似,你可以測(cè)試一個(gè)對(duì)象是否符合特定的協(xié)議。Java在類(lèi)和接口的情況下都使用instanceof 方法搞定,但Objective-C使用了一個(gè)更笨重的方法。在測(cè)試是否合規(guī)的時(shí)候,應(yīng)該使用conformsToProtocol:方法:
- BOOL conforms = [obj conformsToProtocol:@protocol(MyInterface)];
檢查方法是否存在對(duì)于像我這樣Java和C++的老手來(lái)說(shuō),如果不知道一個(gè)對(duì)象是否實(shí)現(xiàn)了一個(gè)方法就很奇怪了。但是Objective-C的類(lèi)很大程度上是動(dòng)態(tài)的,你就需要檢查你需要的方法是否存在。這就需要respondsToSelector:方法。如下代碼就是檢查接收者是否實(shí)現(xiàn)(或者繼承)了指定方法:
- if([obj respondsToSelector:@selector(aMethod:)])
- { // it's there, so we can call it [obj aMethod:YES];
- }
當(dāng)然,利用Objective-C的反射你可以做更多的事情,這里我只是嘗試談?wù)?strong>反射機(jī)制最常見(jiàn)的應(yīng)用。如果你需要在你的軟件中加入核心的動(dòng)態(tài)特性,你就需要熟悉下這些文檔:
- Runtime Programming Guide: Introduction Runtime Reference
小結(jié):解析Objective-C反射的內(nèi)容介紹完了,希望通過(guò)本文的學(xué)習(xí)能對(duì)你有所幫助!